Commit 9706fce0 authored by Manish Singh's avatar Manish Singh Committed by Manish Singh

Support for custom plug-in interpreters, independent of OS support.

2005-02-20  Manish Singh  <yosh@gimp.org>

        Support for custom plug-in interpreters, independent of OS support.

        * app/core/Makefile.am
        * app/core/core-types.h
        * app/core/gimpinterpreterdb.[ch]: implemented GimpInterpreterDB,
        which handles registering and resolving custom plug-in interpreters.

        * app/core/gimp.[ch]: keep a GimpInterpreterDB around.

        * app/config/gimpcoreconfig.[ch]
        * app/config/gimprc-blurbs.h
        * app/dialogs/preferences-dialog.c
        * app/dialogs/user-install-dialog.c
        * app/widgets/gimphelp-ids.h: interpreter-path config stuff.

        * app/plug-in/plug-in.c: use registered interpreters when running
        plug-ins.

        * themes/Default/images/preferences/Makefile.am
        * themes/Default/images/preferences/folders-interp.png: just copied
        folders-plug-ins.png here, need a better one.

        * data/interpreters/Makefile.am: creates system interpreter directory.

        * data/interpreters/default.interp: sample interpreter file info.

        * data/Makefile.am
        * configure.in: add data/interpreters directory.

        * plug-ins/pygimp/Makefile.am: install pygimp.interp, which configures
        the python interpreter to point to the python we were built with. Also
        register the .py extension.

        * etc/gimprc
        * docs/gimprc.5.in: regenerated
parent fd809bfe
2005-02-20 Manish Singh <yosh@gimp.org>
Support for custom plug-in interpreters, independent of OS support.
* app/core/Makefile.am
* app/core/core-types.h
* app/core/gimpinterpreterdb.[ch]: implemented GimpInterpreterDB,
which handles registering and resolving custom plug-in interpreters.
* app/core/gimp.[ch]: keep a GimpInterpreterDB around.
* app/config/gimpcoreconfig.[ch]
* app/config/gimprc-blurbs.h
* app/dialogs/preferences-dialog.c
* app/dialogs/user-install-dialog.c
* app/widgets/gimphelp-ids.h: interpreter-path config stuff.
* app/plug-in/plug-in.c: use registered interpreters when running
plug-ins.
* themes/Default/images/preferences/Makefile.am
* themes/Default/images/preferences/folders-interp.png: just copied
folders-plug-ins.png here, need a better one.
* data/interpreters/Makefile.am: creates system interpreter directory.
* data/interpreters/default.interp: sample interpreter file info.
* data/Makefile.am
* configure.in: add data/interpreters directory.
* plug-ins/pygimp/Makefile.am: install pygimp.interp, which configures
the python interpreter to point to the python we were built with. Also
register the .py extension.
* etc/gimprc
* docs/gimprc.5.in: regenerated
2005-02-20 Jay Cox <jaycox@gimp.org>
* plug-ins/common/psd.c: Fix layer mask support. Addresses bug
......
......@@ -73,6 +73,7 @@ enum
PROP_INTERPOLATION_TYPE,
PROP_PLUG_IN_PATH,
PROP_MODULE_PATH,
PROP_INTERPRETER_PATH,
PROP_ENVIRON_PATH,
PROP_BRUSH_PATH,
PROP_BRUSH_PATH_WRITABLE,
......@@ -169,6 +170,11 @@ gimp_core_config_class_init (GimpCoreConfigClass *klass)
GIMP_CONFIG_PATH_DIR_LIST,
gimp_config_build_plug_in_path ("modules"),
GIMP_CONFIG_PARAM_RESTART);
GIMP_CONFIG_INSTALL_PROP_PATH (object_class, PROP_INTERPRETER_PATH,
"interpreter-path", INTERPRETER_PATH_BLURB,
GIMP_CONFIG_PATH_DIR_LIST,
gimp_config_build_plug_in_path ("interpreters"),
GIMP_CONFIG_PARAM_RESTART);
GIMP_CONFIG_INSTALL_PROP_PATH (object_class, PROP_ENVIRON_PATH,
"environ-path", ENVIRON_PATH_BLURB,
GIMP_CONFIG_PATH_DIR_LIST,
......@@ -357,6 +363,7 @@ gimp_core_config_finalize (GObject *object)
g_free (core_config->plug_in_path);
g_free (core_config->module_path);
g_free (core_config->interpreter_path);
g_free (core_config->environ_path);
g_free (core_config->brush_path);
g_free (core_config->brush_path_writable);
......@@ -408,6 +415,10 @@ gimp_core_config_set_property (GObject *object,
g_free (core_config->module_path);
core_config->module_path = g_value_dup_string (value);
break;
case PROP_INTERPRETER_PATH:
g_free (core_config->interpreter_path);
core_config->interpreter_path = g_value_dup_string (value);
break;
case PROP_ENVIRON_PATH:
g_free (core_config->environ_path);
core_config->environ_path = g_value_dup_string (value);
......@@ -559,6 +570,9 @@ gimp_core_config_get_property (GObject *object,
case PROP_MODULE_PATH:
g_value_set_string (value, core_config->module_path);
break;
case PROP_INTERPRETER_PATH:
g_value_set_string (value, core_config->interpreter_path);
break;
case PROP_ENVIRON_PATH:
g_value_set_string (value, core_config->environ_path);
break;
......
......@@ -43,6 +43,7 @@ struct _GimpCoreConfig
GimpInterpolationType interpolation_type;
gchar *plug_in_path;
gchar *module_path;
gchar *interpreter_path;
gchar *environ_path;
gchar *brush_path;
gchar *brush_path_writable;
......
......@@ -173,6 +173,9 @@ N_("Install a private colormap; might be useful on 8-bit (256 colors) displays."
N_("Sets the level of interpolation used for scaling and other " \
"transformations.")
#define INTERPRETER_PATH_BLURB \
"Sets the interpreter search path."
#define LAST_OPENED_SIZE_BLURB \
N_("How many recently opened image filenames to keep on the File menu.")
......
......@@ -158,6 +158,8 @@ libappcore_a_sources = \
gimpimagefile.h \
gimpimagemap.c \
gimpimagemap.h \
gimpinterpreterdb.c \
gimpinterpreterdb.h \
gimpitem.c \
gimpitem.h \
gimpitem-linked.c \
......
......@@ -113,6 +113,7 @@ typedef struct _GimpEnvironTable GimpEnvironTable;
/* typedef struct _GimpGrid GimpGrid; in config-types.h */
typedef struct _GimpImagefile GimpImagefile;
typedef struct _GimpImageMap GimpImageMap;
typedef struct _GimpInterpreterDB GimpInterpreterDB;
typedef struct _GimpParasiteList GimpParasiteList;
typedef struct _GimpPdbProgress GimpPdbProgress;
typedef struct _GimpProjection GimpProjection;
......
......@@ -59,6 +59,7 @@
#include "gimpgradient-load.h"
#include "gimpimage.h"
#include "gimpimagefile.h"
#include "gimpinterpreterdb.h"
#include "gimplist.h"
#include "gimpmarshal.h"
#include "gimppalette.h"
......@@ -230,6 +231,7 @@ gimp_init (Gimp *gimp)
gimp_modules_init (gimp);
gimp->interpreter_db = gimp_interpreter_db_new ();
gimp->environ_table = gimp_environ_table_new ();
gimp->plug_in_debug = NULL;
......@@ -432,6 +434,12 @@ gimp_finalize (GObject *object)
gimp->environ_table = NULL;
}
if (gimp->interpreter_db)
{
g_object_unref (gimp->interpreter_db);
gimp->interpreter_db = NULL;
}
if (gimp->module_db)
gimp_modules_exit (gimp);
......@@ -635,6 +643,12 @@ gimp_real_initialize (Gimp *gimp,
(* status_callback) (_("Procedural Database"), NULL, -1);
procedural_db_init_procs (gimp, status_callback);
(* status_callback) (_("Plug-In Interpreters"), "", -1);
path = gimp_config_path_expand (gimp->config->interpreter_path, TRUE, NULL);
gimp_interpreter_db_load (gimp->interpreter_db, path);
g_free (path);
(* status_callback) (_("Plug-In Environment"), "", -1);
path = gimp_config_path_expand (gimp->config->environ_path, TRUE, NULL);
......
......@@ -81,6 +81,7 @@ struct _Gimp
PlugInProcDef *last_plug_in;
PlugInShm *plug_in_shm;
GimpInterpreterDB *interpreter_db;
GimpEnvironTable *environ_table;
GimpPlugInDebug *plug_in_debug;
......
/* The GIMP -- an image manipulation program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* gimpinterpreterdb.c
* (C) 2005 Manish Singh <yosh@gimp.org>
*
* 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
* The binfmt_misc bits are derived from linux/fs/binfmt_misc.c
* Copyright (C) 1997 Richard Günther
*/
/*
* The sh-bang code is derived from linux/fs/binfmt_script.c
* Copyright (C) 1996 Martin von Löwis
* original #!-checking implemented by tytso.
*/
#include "config.h"
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <fcntl.h>
#include <glib-object.h>
#include <glib/gstdio.h>
#ifdef G_OS_WIN32
#include <io.h>
#endif
#ifndef _O_BINARY
#define _O_BINARY 0
#endif
#include "libgimpbase/gimpbase.h"
#include "core-types.h"
#include "gimpinterpreterdb.h"
#include "gimp-intl.h"
#define BUFSIZE 4096
typedef struct _GimpInterpreterMagic GimpInterpreterMagic;
struct _GimpInterpreterMagic
{
gulong offset;
gchar *magic;
gchar *mask;
guint size;
gchar *program;
};
static void gimp_interpreter_db_class_init (GimpInterpreterDBClass *class);
static void gimp_interpreter_db_init (GimpInterpreterDB *db);
static void gimp_interpreter_db_finalize (GObject *object);
static void gimp_interpreter_db_load_interp_file (const GimpDatafileData *file_data,
gpointer user_data);
static void gimp_interpreter_db_add_program (GimpInterpreterDB *db,
const GimpDatafileData *file_data,
gchar *buffer);
static void gimp_interpreter_db_add_binfmt_misc (GimpInterpreterDB *db,
const GimpDatafileData *file_data,
gchar *buffer);
static gboolean gimp_interpreter_db_add_extension (GimpInterpreterDB *db,
gchar **tokens);
static gboolean gimp_interpreter_db_add_magic (GimpInterpreterDB *db,
gchar **tokens);
static void gimp_interpreter_db_clear_magics (GimpInterpreterDB *db);
static void gimp_interpreter_db_resolve_programs (GimpInterpreterDB *db);
static GObjectClass *parent_class = NULL;
GType
gimp_interpreter_db_get_type (void)
{
static GType interpreter_db_type = 0;
if (! interpreter_db_type)
{
static const GTypeInfo interpreter_db_info =
{
sizeof (GimpInterpreterDBClass),
NULL, /* base_init */
NULL, /* base_finalize */
(GClassInitFunc) gimp_interpreter_db_class_init,
NULL, /* class_finalize */
NULL, /* class_data */
sizeof (GimpInterpreterDB),
0, /* n_preallocs */
(GInstanceInitFunc) gimp_interpreter_db_init,
};
interpreter_db_type = g_type_register_static (G_TYPE_OBJECT,
"GimpInterpreterDB",
&interpreter_db_info, 0);
}
return interpreter_db_type;
}
static void
gimp_interpreter_db_class_init (GimpInterpreterDBClass *class)
{
GObjectClass *object_class;
object_class = G_OBJECT_CLASS (class);
parent_class = g_type_class_peek_parent (class);
object_class->finalize = gimp_interpreter_db_finalize;
}
static void
gimp_interpreter_db_init (GimpInterpreterDB *db)
{
db->programs = NULL;
db->magics = NULL;
db->magic_names = NULL;
db->extensions = NULL;
db->extension_names = NULL;
}
static void
gimp_interpreter_db_finalize (GObject *object)
{
GimpInterpreterDB *db;
db = GIMP_INTERPRETER_DB (object);
gimp_interpreter_db_clear (db);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
GimpInterpreterDB *
gimp_interpreter_db_new (void)
{
return g_object_new (GIMP_TYPE_INTERPRETER_DB, NULL);
}
void
gimp_interpreter_db_load (GimpInterpreterDB *db,
const gchar *interp_path)
{
g_return_if_fail (GIMP_IS_INTERPRETER_DB (db));
gimp_interpreter_db_clear (db);
db->programs = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, g_free);
db->extensions = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, g_free);
db->magic_names = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, NULL);
db->extension_names = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, NULL);
gimp_datafiles_read_directories (interp_path,
G_FILE_TEST_EXISTS,
gimp_interpreter_db_load_interp_file,
db);
gimp_interpreter_db_resolve_programs (db);
}
void
gimp_interpreter_db_clear (GimpInterpreterDB *db)
{
g_return_if_fail (GIMP_IS_INTERPRETER_DB (db));
if (db->magic_names)
{
g_hash_table_destroy (db->magic_names);
db->magic_names = NULL;
}
if (db->extension_names)
{
g_hash_table_destroy (db->extension_names);
db->extension_names = NULL;
}
if (db->programs)
{
g_hash_table_destroy (db->programs);
db->programs = NULL;
}
if (db->extensions)
{
g_hash_table_destroy (db->extensions);
db->extensions = NULL;
}
gimp_interpreter_db_clear_magics (db);
}
static void
gimp_interpreter_db_load_interp_file (const GimpDatafileData *file_data,
gpointer user_data)
{
GimpInterpreterDB *db;
FILE *interp_file;
gchar buffer[4096];
gsize len;
db = GIMP_INTERPRETER_DB (user_data);
interp_file = g_fopen (file_data->filename, "r");
if (! interp_file)
return;
while (fgets (buffer, sizeof (buffer), interp_file))
{
/* Skip comments */
if (buffer[0] == '#')
continue;
len = strlen (buffer) - 1;
/* Skip too long lines */
if (buffer[len] != '\n')
continue;
buffer[len] = '\0';
if (g_ascii_isalnum (buffer[0]) || (buffer[0] == '/'))
gimp_interpreter_db_add_program (db, file_data, buffer);
else if (! g_ascii_isspace (buffer[0]) && (buffer[0] != '\0'))
gimp_interpreter_db_add_binfmt_misc (db, file_data, buffer);
}
fclose (interp_file);
}
static void
gimp_interpreter_db_add_program (GimpInterpreterDB *db,
const GimpDatafileData *file_data,
gchar *buffer)
{
gchar *name, *program, *p;
p = strchr (buffer, '=');
if (! p)
return;
*p = '\0';
name = buffer;
program = p + 1;
if (! g_file_test (program, G_FILE_TEST_IS_EXECUTABLE))
{
g_message (_("Bad interpreter referenced in interpreter file %s: %s"),
gimp_filename_to_utf8 (file_data->filename),
gimp_filename_to_utf8 (program));
return;
}
if (! g_hash_table_lookup (db->programs, name))
g_hash_table_insert (db->programs, g_strdup (name), g_strdup (program));
}
static void
gimp_interpreter_db_add_binfmt_misc (GimpInterpreterDB *db,
const GimpDatafileData *file_data,
gchar *buffer)
{
gchar **tokens = NULL;
gchar *name, *type, *program;
gsize count;
gchar del[2];
count = strlen (buffer);
if ((count < 10) || (count > 255))
goto bail;
del[0] = *buffer;
del[1] = '\0';
memset (buffer + count, del[0], 8);
tokens = g_strsplit (buffer + 1, del, -1);
name = tokens[0];
type = tokens[1];
program = tokens[5];
if (name[0] == '\0' || program == '\0' || type[0] == '\0' || type[1] != '\0')
goto bail;
switch (type[0])
{
case 'E':
if (! gimp_interpreter_db_add_extension (db, tokens))
goto bail;
break;
case 'M':
if (! gimp_interpreter_db_add_magic (db, tokens))
goto bail;
break;
default:
goto bail;
}
goto out;
bail:
g_message (_("Bad binary format string in interpreter file %s"),
gimp_filename_to_utf8 (file_data->filename));
out:
g_strfreev (tokens);
}
static gboolean
gimp_interpreter_db_add_extension (GimpInterpreterDB *db,
gchar **tokens)
{
gchar *name, *extension, *program;
name = tokens[0];
extension = tokens[3];
program = tokens[5];
if (! g_hash_table_lookup (db->extension_names, name))
{
if (extension[0] == '\0' || extension[0] == '/')
return FALSE;
program = g_strdup (program);
g_hash_table_insert (db->extensions, g_strdup (extension), program);
g_hash_table_insert (db->extension_names, g_strdup (name), program);
}
return TRUE;
}
static gboolean
scanarg (gchar *s)
{
gchar c;
while ((c = *s++) != '\0')
{
if (c == '\\' && *s == 'x')
{
s++;
if (! g_ascii_isxdigit (*s++))
return FALSE;
if (! g_ascii_isxdigit (*s++))
return FALSE;
}
}
return TRUE;
}
static guint
unquote (gchar *from)
{
gchar c, *s = from, *p = from;
while ((c = *s++) != '\0')
{
if (c == '\\' && *s == 'x')
{
s++;
*p = g_ascii_xdigit_value (*s++) << 4;
*p++ |= g_ascii_xdigit_value (*s++);
continue;
}
*p++ = c;
}
return p - from;
}
static gboolean
gimp_interpreter_db_add_magic (GimpInterpreterDB *db,
gchar **tokens)
{
GimpInterpreterMagic *interp_magic;
gchar *name, *num, *magic, *mask, *program;
gulong offset;
guint size;
name = tokens[0];
num = tokens[2];
magic = tokens[3];
mask = tokens[4];
program = tokens[5];
if (! g_hash_table_lookup (db->magic_names, name))
{
if (num[0] != '\0')
{
offset = strtoul (num, &num, 10);
if (num[0] != '\0')
return FALSE;
if (offset > (BUFSIZE / 4))
return FALSE;
}
else
offset = 0;
if (! scanarg (magic))
return FALSE;
if (! scanarg (mask))
return FALSE;
size = unquote (magic);
if ((size + offset) > (BUFSIZE / 2))
return FALSE;
if (mask[0] == '\0')
mask = NULL;
else if (unquote (mask) != size)