gplugin/gplugin
Clone
Summary
Browse
Changes
Graph
Add more details to basic plugin names
19 months ago, Elliott Sales de Andrade
7cd3caa3f514
Add more details to basic plugin names
Just so there aren't "basic plugin" a bunch of times over in the list.
Testing Done:
Checked viewer and ran `ninja test`.
Reviewed at https://reviews.imfreedom.org/r/1837/
/*
* Copyright (C) 2011-2020 Gary Kramlich <grim@reaperworld.com>
*
* This library 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 library 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 library; if not, see <https://www.gnu.org/licenses/>.
*/
#include
<gmodule.h>
#include
<glib/gi18n-lib.h>
#include
<gplugin/gplugin-core.h>
#include
<gplugin/gplugin-native-loader.h>
#include
<gplugin/gplugin-native-plugin.h>
#include
<gplugin/gplugin-private.h>
#define GPLUGIN_QUERY_SYMBOL "gplugin_query"
#define GPLUGIN_LOAD_SYMBOL "gplugin_load"
#define GPLUGIN_UNLOAD_SYMBOL "gplugin_unload"
/**
* GPluginNativeLoader:
*
* A #GPluginLoader subclass that is able to load native plugins.
*/
/**
* GPLUGIN_NATIVE_PLUGIN_ABI_VERSION:
*
* The ABI version of the #GPluginNativeLoader. Your plugin should use this
* as the value for #abi_version when call #gplugin_plugin_info_new.
*/
struct
_GPluginNativeLoader
{
GPluginLoader
parent
;
};
G_DEFINE_TYPE
(
GPluginNativeLoader
,
gplugin_native_loader
,
GPLUGIN_TYPE_LOADER
)
/******************************************************************************
* Helpers
*****************************************************************************/
static
gpointer
gplugin_native_loader_lookup_symbol
(
GModule
*
module
,
const
gchar
*
name
,
GError
**
error
)
{
gpointer
symbol
=
NULL
;
g_return_val_if_fail
(
module
!=
NULL
,
NULL
);
if
(
!
g_module_symbol
(
module
,
name
,
&
symbol
))
{
g_set_error
(
error
,
GPLUGIN_DOMAIN
,
0
,
_
(
"symbol %s was not found"
),
name
);
return
NULL
;
}
return
symbol
;
}
static
GModule
*
gplugin_native_loader_open
(
const
gchar
*
filename
,
GModuleFlags
flags
,
GError
**
error
)
{
GModule
*
module
=
NULL
;
module
=
g_module_open
(
filename
,
flags
);
if
(
module
)
return
module
;
if
(
error
)
{
const
gchar
*
msg
=
g_module_error
();
*
error
=
g_error_new
(
GPLUGIN_DOMAIN
,
0
,
_
(
"Failed to open plugin '%s': %s"
),
filename
,
(
msg
)
?
msg
:
_
(
"Unknown error"
));
}
return
NULL
;
}
/******************************************************************************
* GPluginLoaderInterface API
*****************************************************************************/
static
GSList
*
gplugin_native_loader_supported_extensions
(
G_GNUC_UNUSED
GPluginLoader
*
l
)
{
GSList
*
exts
=
g_slist_append
(
NULL
,
G_MODULE_SUFFIX
);
#if defined(__APPLE__) || defined(__MACH__)
/* G_MODULE_SUFFIX only requests `.so` on not windows, and both .so and
* .dylib are used on macos, so add dylib if we're on macos.
* See: https://gitlab.gnome.org/GNOME/glib/issues/1413
*/
exts
=
g_slist_append
(
exts
,
"dylib"
);
#endif
return
exts
;
}
static
GPluginPluginInfo
*
gplugin_native_loader_open_and_query
(
const
gchar
*
filename
,
GModule
**
module
,
GModuleFlags
flags
,
GPluginNativePluginQueryFunc
*
query
,
GError
**
error
)
{
GPluginPluginInfo
*
info
=
NULL
;
*
module
=
gplugin_native_loader_open
(
filename
,
flags
,
error
);
if
(
*
module
==
NULL
)
{
return
NULL
;
}
else
if
(
error
&&
*
error
)
{
g_module_close
(
*
module
);
*
module
=
NULL
;
return
NULL
;
}
*
query
=
gplugin_native_loader_lookup_symbol
(
*
module
,
GPLUGIN_QUERY_SYMBOL
,
error
);
if
((
*
query
==
NULL
)
||
(
error
&&
*
error
))
{
g_module_close
(
*
module
);
*
module
=
NULL
;
return
NULL
;
}
info
=
((
GPluginNativePluginQueryFunc
)(
*
query
))(
error
);
if
(
error
&&
*
error
)
{
g_module_close
(
*
module
);
*
module
=
NULL
;
return
NULL
;
}
return
info
;
}
static
GPluginPlugin
*
gplugin_native_loader_query
(
GPluginLoader
*
loader
,
const
gchar
*
filename
,
GError
**
error
)
{
GPluginPlugin
*
plugin
=
NULL
;
GPluginPluginInfo
*
info
=
NULL
;
GPluginNativePluginLoadFunc
load
=
NULL
;
GPluginNativePluginQueryFunc
query
=
NULL
;
GPluginNativePluginUnloadFunc
unload
=
NULL
;
GModule
*
module
=
NULL
;
info
=
gplugin_native_loader_open_and_query
(
filename
,
&
module
,
G_MODULE_BIND_LOCAL
,
&
query
,
error
);
if
(
!
GPLUGIN_IS_PLUGIN_INFO
(
info
))
{
if
(
error
&&
*
error
==
NULL
)
{
g_set_error_literal
(
error
,
GPLUGIN_DOMAIN
,
0
,
_
(
"the query function did not return a "
"GPluginPluginInfo instance"
));
}
return
NULL
;
}
if
(
gplugin_plugin_info_get_bind_global
(
info
))
{
g_module_close
(
module
);
g_object_unref
(
G_OBJECT
(
info
));
info
=
gplugin_native_loader_open_and_query
(
filename
,
&
module
,
0
,
&
query
,
error
);
if
(
!
GPLUGIN_IS_PLUGIN_INFO
(
info
))
{
if
(
error
&&
*
error
==
NULL
)
{
g_set_error_literal
(
error
,
GPLUGIN_DOMAIN
,
0
,
_
(
"the query function did not return a "
"GPluginPluginInfo instance"
));
}
return
NULL
;
}
}
/* now look for the load symbol */
load
=
gplugin_native_loader_lookup_symbol
(
module
,
GPLUGIN_LOAD_SYMBOL
,
error
);
if
(
error
&&
*
error
)
{
g_module_close
(
module
);
g_object_unref
(
G_OBJECT
(
info
));
return
NULL
;
}
/* now look for the unload symbol */
unload
=
gplugin_native_loader_lookup_symbol
(
module
,
GPLUGIN_UNLOAD_SYMBOL
,
error
);
if
(
error
&&
*
error
)
{
g_module_close
(
module
);
g_object_unref
(
G_OBJECT
(
info
));
return
NULL
;
}
/* now create the actual plugin instance */
/* clang-format off */
plugin
=
g_object_new
(
GPLUGIN_TYPE_NATIVE_PLUGIN
,
"module"
,
module
,
"info"
,
info
,
"load-func"
,
load
,
"unload-func"
,
unload
,
"loader"
,
loader
,
"filename"
,
filename
,
NULL
);
/* clang-format on */
/* now that the plugin instance owns the info, remove our ref */
g_object_unref
(
G_OBJECT
(
info
));
if
(
!
GPLUGIN_IS_NATIVE_PLUGIN
(
plugin
))
{
g_module_close
(
module
);
g_set_error_literal
(
error
,
GPLUGIN_DOMAIN
,
0
,
_
(
"failed to create plugin instance"
));
return
NULL
;
}
return
plugin
;
}
static
gboolean
gplugin_native_loader_load
(
G_GNUC_UNUSED
GPluginLoader
*
loader
,
GPluginPlugin
*
plugin
,
GError
**
error
)
{
GPluginNativePluginLoadFunc
func
;
g_return_val_if_fail
(
plugin
!=
NULL
,
FALSE
);
g_return_val_if_fail
(
GPLUGIN_IS_NATIVE_PLUGIN
(
plugin
),
FALSE
);
/* get and call the function */
g_object_get
(
G_OBJECT
(
plugin
),
"load-func"
,
&
func
,
NULL
);
if
(
!
func
(
plugin
,
error
))
{
if
(
error
&&
*
error
==
NULL
)
g_set_error_literal
(
error
,
GPLUGIN_DOMAIN
,
0
,
_
(
"unknown failure"
));
return
FALSE
;
}
return
TRUE
;
}
static
gboolean
gplugin_native_loader_unload
(
G_GNUC_UNUSED
GPluginLoader
*
loader
,
GPluginPlugin
*
plugin
,
gboolean
shutdown
,
GError
**
error
)
{
GPluginNativePluginUnloadFunc
func
;
g_return_val_if_fail
(
plugin
!=
NULL
,
FALSE
);
g_return_val_if_fail
(
GPLUGIN_IS_NATIVE_PLUGIN
(
plugin
),
FALSE
);
/* get the function */
g_object_get
(
G_OBJECT
(
plugin
),
"unload-func"
,
&
func
,
NULL
);
/* validate the function */
if
(
func
==
NULL
)
{
gchar
*
filename
=
gplugin_plugin_get_filename
(
plugin
);
g_warning
(
_
(
"unload function for %s is NULL"
),
filename
);
g_free
(
filename
);
return
FALSE
;
}
/* now call the function */
if
(
!
func
(
plugin
,
shutdown
,
error
))
{
if
(
error
&&
*
error
==
NULL
)
g_set_error_literal
(
error
,
GPLUGIN_DOMAIN
,
0
,
_
(
"unknown failure"
));
return
FALSE
;
}
return
TRUE
;
}
static
void
gplugin_native_loader_init
(
G_GNUC_UNUSED
GPluginNativeLoader
*
loader
)
{
}
static
void
gplugin_native_loader_class_init
(
GPluginNativeLoaderClass
*
klass
)
{
GPluginLoaderClass
*
loader_class
=
GPLUGIN_LOADER_CLASS
(
klass
);
loader_class
->
supported_extensions
=
gplugin_native_loader_supported_extensions
;
loader_class
->
query
=
gplugin_native_loader_query
;
loader_class
->
load
=
gplugin_native_loader_load
;
loader_class
->
unload
=
gplugin_native_loader_unload
;
}
/******************************************************************************
* Public API
*****************************************************************************/
/**
* gplugin_native_loader_new:
*
* Create a new instance of the native plugin loader.
*
* Typically you won't need to call this directly as GPlugin will create it
* unless #GPLUGIN_CORE_FLAGS_DISABLE_NATIVE_LOADER is passed to
* gplugin_init().
*
* Returns: (transfer full): The new instance.
*
* Since: 0.34.0
*/
GPluginLoader
*
gplugin_native_loader_new
(
void
)
{
/* clang-format off */
return
g_object_new
(
GPLUGIN_TYPE_NATIVE_LOADER
,
"id"
,
"gplugin-native"
,
NULL
);
/* clang-format on */
}