blob: 8d024252272bd62c0fa4ef2b9b61741cd13c5e57 [file] [log] [blame]
/* Start up the world of vips.
*
* 7/1/04 JC
* - 1st version
* 7/6/05
* - g_type_init() too, so we can use gobject
* 2/9/06
* - also set g_prg_name() and load plugins
* 8/12/06
* - add liboil support
* 5/2/07
* - stop a loop if we're called recursively during VIPS startup ... it
* can happen if (for example) im_guess_prefix() fails and tries to
* i18n an error message (thanks Christian)
* 8/6/07
* - just warn if plugins fail to load correctly: too annoying to have
* VIPS refuse to start because of a dodgy plugin
* 7/11/07
* - progress feedback option
* 5/8/08
* - load plugins from libdir/vips-x.x
* 5/10/09
* - gtkdoc comments
*/
/*
This file is part of VIPS.
VIPS is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser 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
*/
/*
These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
*/
/*
#define DEBUG
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /*HAVE_CONFIG_H*/
#include <vips/intl.h>
#include <string.h>
#include <vips/vips.h>
#include <vips/thread.h>
#include <vips/internal.h>
#ifdef HAVE_LIBOIL
#include <liboil/liboil.h>
#endif /*HAVE_LIBOIL*/
#ifdef WITH_DMALLOC
#include <dmalloc.h>
#endif /*WITH_DMALLOC*/
/* Use in various small places where we need a mutex and it's not worth
* making a private one.
*/
GMutex *im__global_lock = NULL;
/* Keep a copy of the argv0 here.
*/
static char *im__argv0 = NULL;
/**
* im_get_argv0:
*
* See also: im_init_world().
*
* Returns: a pointer to an internal copy of the argv0 string passed to
* im_init_world(). Do not free this value
*/
const char *
im_get_argv0( void )
{
return( im__argv0 );
}
/**
* im_init_world:
* @argv0: name of application
*
* im_init_world() starts up the world of VIPS. You should call this on
* program startup before using any other VIPS operations. If you do not call
* im_init_world(), VIPS will call it for you when you use your first VIPS
* operation, but
* it may not be able to get hold of @argv0 and VIPS may therefore be unable
* to find its data files. It is much better to call this function yourself.
*
* im_init_world() does approximately the following:
*
* <itemizedlist>
* <listitem>
* <para>initialises any libraries that VIPS is using, including GObject
* and the threading system, if neccessary</para>
* </listitem>
* <listitem>
* <para>guesses where the VIPS data files are and sets up
* internationalisation --- see im_guess_prefix()
* </para>
* </listitem>
* <listitem>
* <para>loads any plugins from $libdir/vips-x.y, where x and y are the
* major and minor version numbers for this VIPS.
* </para>
* </listitem>
* </itemizedlist>
*
* Example:
*
* |[
* int main( int argc, char **argv )
* {
* if( im_init_world( argv[0] ) )
* error_exit( "unable to start VIPS" );
*
* return( 0 );
* }
* ]|
*
* See also: im_get_option_group(), im_version(), im_guess_prefix(),
* im_guess_libdir().
*
* Returns: 0 on success, -1 otherwise
*/
int
im_init_world( const char *argv0 )
{
static gboolean started = FALSE;
static gboolean done = FALSE;
char *prgname;
const char *prefix;
const char *libdir;
char name[256];
/* Two stage done handling: 'done' means we've completed, 'started'
* means we're currently initialising. Use this to prevent recursive
* invocation.
*/
if( done )
/* Called more than once, we succeeded, just return OK.
*/
return( 0 );
if( started )
/* Recursive invocation, something has broken horribly.
* Hopefully the first init will handle it.
*/
return( 0 );
started = TRUE;
IM_SETSTR( im__argv0, argv0 );
/* Need gobject etc.
*/
g_type_init();
#ifdef G_THREADS_ENABLED
if( !g_thread_supported() )
g_thread_init( NULL );
#endif /*G_THREADS_ENABLED*/
if( !im__global_lock )
im__global_lock = g_mutex_new();
prgname = g_path_get_basename( argv0 );
g_set_prgname( prgname );
g_free( prgname );
/* Try to discover our prefix.
*/
if( !(prefix = im_guess_prefix( argv0, "VIPSHOME" )) ||
!(libdir = im_guess_libdir( argv0, "VIPSHOME" )) )
return( -1 );
/* Get i18n .mo files from $VIPSHOME/share/locale/.
*/
im_snprintf( name, 256,
"%s" G_DIR_SEPARATOR_S "share" G_DIR_SEPARATOR_S "locale",
prefix );
bindtextdomain( GETTEXT_PACKAGE, name );
bind_textdomain_codeset( GETTEXT_PACKAGE, "UTF-8" );
/* Register base vips types.
*/
im__meta_init_types();
im__format_init();
vips__interpolate_init();
/* Load up any plugins in the vips libdir. We don't error on failure,
* it's too annoying to have VIPS refuse to start because of a broken
* plugin.
*/
if( im_load_plugins( "%s/vips-%d.%d",
libdir, IM_MAJOR_VERSION, IM_MINOR_VERSION ) ) {
im_warn( "im_init_world", "%s", im_error_buffer() );
im_error_clear();
}
/* Also load from libdir. This is old and slightly broken behaviour
* :-( kept for back compat convenience.
*/
if( im_load_plugins( "%s", libdir ) ) {
im_warn( "im_init_world", "%s", im_error_buffer() );
im_error_clear();
}
/* Start up the buffer cache.
*/
im__buffer_init();
#ifdef HAVE_LIBOIL
{
#ifdef DEBUG
GTimer *timer = g_timer_new();
#endif /*DEBUG*/
oil_init();
#ifdef DEBUG
/* 0.3 is only about 0.1s on my laptop, but this may take longer in
* future.
*/
printf( "oil_init: %gs\n", g_timer_elapsed( timer, NULL ) );
g_timer_destroy( timer );
#endif /*DEBUG*/
}
#endif /*HAVE_LIBOIL*/
done = TRUE;
return( 0 );
}
const char *
im__gettext( const char *msgid )
{
/* Pass in a nonsense name for argv0 ... this init path is only here
* for old programs which are missing an im_init_world() call. We need
* i18n set up before we can translate.
*/
if( im_init_world( "giant_banana" ) )
im_error_clear();
return( dgettext( GETTEXT_PACKAGE, msgid ) );
}
const char *
im__ngettext( const char *msgid, const char *plural, unsigned long int n )
{
if( im_init_world( "giant_banana" ) )
im_error_clear();
return( dngettext( GETTEXT_PACKAGE, msgid, plural, n ) );
}
static GOptionEntry option_entries[] = {
{ "vips-concurrency", 'c', 0, G_OPTION_ARG_INT, &im__concurrency,
N_( "evaluate with N concurrent threads" ), "N" },
{ "vips-tile-width", 'w', 0, G_OPTION_ARG_INT, &im__tile_width,
N_( "set tile width to N (DEBUG)" ), "N" },
{ "vips-tile-height", 'h', 0, G_OPTION_ARG_INT, &im__tile_height,
N_( "set tile height to N (DEBUG)" ), "N" },
{ "vips-thinstrip-height", 't', 0,
G_OPTION_ARG_INT, &im__thinstrip_height,
N_( "set thinstrip height to N (DEBUG)" ), "N" },
{ "vips-fatstrip-height", 'f', 0,
G_OPTION_ARG_INT, &im__fatstrip_height,
N_( "set fatstrip height to N (DEBUG)" ), "N" },
{ "vips-progress", 'p', 0, G_OPTION_ARG_NONE, &im__progress,
N_( "show progress feedback" ), NULL },
{ NULL }
};
/**
* im_get_option_group:
*
* im_get_option_group() returns a GOptionGroup containing various VIPS
* command-line options. It can be used with GOption to help
* parse argc/argv.
*
* See also: im_version(), im_guess_prefix(),
* im_guess_libdir(), im_init_world().
*
* Returns: a GOptionGroup for VIPS, see GOption
*/
GOptionGroup *
im_get_option_group( void )
{
static GOptionGroup *option_group = NULL;
if( !option_group ) {
option_group = g_option_group_new(
"vips", _( "VIPS Options" ), _( "Show VIPS options" ),
NULL, NULL );
g_option_group_add_entries( option_group, option_entries );
}
return( option_group );
}