mirror of
https://github.com/MariaDB/server.git
synced 2025-02-20 20:33:15 +01:00
1396 lines
33 KiB
C
1396 lines
33 KiB
C
/* -*- c-basic-offset: 2 -*- */
|
|
/*
|
|
Copyright(C) 2012-2017 Brazil
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Lesser General Public
|
|
License version 2.1 as published by the Free Software Foundation.
|
|
|
|
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, write to the Free Software
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
|
|
*/
|
|
#include "grn.h"
|
|
#include "grn_ctx_impl_mrb.h"
|
|
#include "grn_proc.h"
|
|
#include <groonga/plugin.h>
|
|
|
|
#include <stdarg.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#include <sys/stat.h>
|
|
#ifdef HAVE_DIRENT_H
|
|
# include <dirent.h>
|
|
#endif /* HAVE_DIRENT_H */
|
|
|
|
#ifndef S_ISREG
|
|
# ifdef _S_IFREG
|
|
# define S_ISREG(mode) (mode & _S_IFREG)
|
|
# endif /* _S_IFREG */
|
|
#endif /* !S_ISREG */
|
|
|
|
#include "grn_db.h"
|
|
#include "grn_plugin.h"
|
|
#include "grn_ctx_impl.h"
|
|
#include "grn_util.h"
|
|
|
|
#ifdef GRN_WITH_MRUBY
|
|
# include <mruby.h>
|
|
#endif /* GRN_WITH_MRUBY */
|
|
|
|
static grn_hash *grn_plugins = NULL;
|
|
static grn_critical_section grn_plugins_lock;
|
|
static grn_ctx grn_plugins_ctx;
|
|
|
|
#ifdef HAVE_DLFCN_H
|
|
# include <dlfcn.h>
|
|
# define grn_dl_open(filename) dlopen(filename, RTLD_LAZY | RTLD_LOCAL)
|
|
# define grn_dl_open_error_label() dlerror()
|
|
# define grn_dl_close(dl) (dlclose(dl) == 0)
|
|
# define grn_dl_close_error_label() dlerror()
|
|
# define grn_dl_sym(dl, symbol) dlsym(dl, symbol)
|
|
# define grn_dl_sym_error_label() dlerror()
|
|
# define grn_dl_clear_error() dlerror()
|
|
#else
|
|
# define grn_dl_open(filename) LoadLibrary(filename)
|
|
# define grn_dl_open_error_label() "LoadLibrary"
|
|
# define grn_dl_close(dl) (FreeLibrary(dl) != 0)
|
|
# define grn_dl_close_error_label() "FreeLibrary"
|
|
# define grn_dl_sym(dl, symbol) ((void *)GetProcAddress(dl, symbol))
|
|
# define grn_dl_sym_error_label() "GetProcAddress"
|
|
# define grn_dl_clear_error()
|
|
#endif
|
|
|
|
#define GRN_PLUGIN_KEY_SIZE(filename) (strlen((filename)) + 1)
|
|
|
|
static char grn_plugins_dir[GRN_ENV_BUFFER_SIZE];
|
|
|
|
void
|
|
grn_plugin_init_from_env(void)
|
|
{
|
|
grn_getenv("GRN_PLUGINS_DIR",
|
|
grn_plugins_dir,
|
|
GRN_ENV_BUFFER_SIZE);
|
|
}
|
|
|
|
static int
|
|
compute_name_size(const char *name, int name_size)
|
|
{
|
|
if (name_size < 0) {
|
|
if (name) {
|
|
name_size = strlen(name);
|
|
} else {
|
|
name_size = 0;
|
|
}
|
|
}
|
|
return name_size;
|
|
}
|
|
|
|
grn_id
|
|
grn_plugin_reference(grn_ctx *ctx, const char *filename)
|
|
{
|
|
grn_id id;
|
|
grn_plugin **plugin = NULL;
|
|
|
|
CRITICAL_SECTION_ENTER(grn_plugins_lock);
|
|
id = grn_hash_get(&grn_plugins_ctx, grn_plugins,
|
|
filename, GRN_PLUGIN_KEY_SIZE(filename),
|
|
(void **)&plugin);
|
|
if (plugin) {
|
|
(*plugin)->refcount++;
|
|
}
|
|
CRITICAL_SECTION_LEAVE(grn_plugins_lock);
|
|
|
|
return id;
|
|
}
|
|
|
|
const char *
|
|
grn_plugin_path(grn_ctx *ctx, grn_id id)
|
|
{
|
|
const char *path;
|
|
grn_plugin *plugin;
|
|
int value_size;
|
|
const char *system_plugins_dir;
|
|
size_t system_plugins_dir_size;
|
|
|
|
if (id == GRN_ID_NIL) {
|
|
return NULL;
|
|
}
|
|
|
|
CRITICAL_SECTION_ENTER(grn_plugins_lock);
|
|
value_size = grn_hash_get_value(&grn_plugins_ctx, grn_plugins, id, &plugin);
|
|
CRITICAL_SECTION_LEAVE(grn_plugins_lock);
|
|
|
|
if (!plugin) {
|
|
return NULL;
|
|
}
|
|
|
|
path = plugin->path;
|
|
system_plugins_dir = grn_plugin_get_system_plugins_dir();
|
|
system_plugins_dir_size = strlen(system_plugins_dir);
|
|
if (strncmp(system_plugins_dir, path, system_plugins_dir_size) == 0) {
|
|
const char *plugin_name = path + system_plugins_dir_size;
|
|
while (plugin_name[0] == '/') {
|
|
plugin_name++;
|
|
}
|
|
/* TODO: remove suffix too? */
|
|
return plugin_name;
|
|
} else {
|
|
return path;
|
|
}
|
|
}
|
|
|
|
#define GRN_PLUGIN_FUNC_PREFIX "grn_plugin_impl_"
|
|
|
|
static grn_rc
|
|
grn_plugin_call_init(grn_ctx *ctx, grn_id id)
|
|
{
|
|
grn_plugin *plugin;
|
|
int size;
|
|
|
|
size = grn_hash_get_value(&grn_plugins_ctx, grn_plugins, id, &plugin);
|
|
if (size == 0) {
|
|
return GRN_INVALID_ARGUMENT;
|
|
}
|
|
|
|
if (plugin->init_func) {
|
|
return plugin->init_func(ctx);
|
|
}
|
|
|
|
return GRN_SUCCESS;
|
|
}
|
|
|
|
#ifdef GRN_WITH_MRUBY
|
|
static grn_rc
|
|
grn_plugin_call_register_mrb(grn_ctx *ctx, grn_id id, grn_plugin *plugin)
|
|
{
|
|
grn_mrb_data *data;
|
|
mrb_state *mrb;
|
|
struct RClass *module;
|
|
struct RClass *plugin_loader_class;
|
|
int arena_index;
|
|
|
|
grn_ctx_impl_mrb_ensure_init(ctx);
|
|
if (ctx->rc != GRN_SUCCESS) {
|
|
return ctx->rc;
|
|
}
|
|
|
|
data = &(ctx->impl->mrb);
|
|
mrb = data->state;
|
|
module = data->module;
|
|
|
|
{
|
|
int added;
|
|
grn_hash_add(ctx, ctx->impl->mrb.registered_plugins,
|
|
&id, sizeof(grn_id), NULL, &added);
|
|
if (!added) {
|
|
return ctx->rc;
|
|
}
|
|
}
|
|
|
|
arena_index = mrb_gc_arena_save(mrb);
|
|
plugin_loader_class = mrb_class_get_under(mrb, module, "PluginLoader");
|
|
mrb_funcall(mrb, mrb_obj_value(plugin_loader_class),
|
|
"load_file", 1, mrb_str_new_cstr(mrb, ctx->impl->plugin_path));
|
|
mrb_gc_arena_restore(mrb, arena_index);
|
|
return ctx->rc;
|
|
}
|
|
#endif /*GRN_WITH_MRUBY */
|
|
|
|
static grn_rc
|
|
grn_plugin_call_register(grn_ctx *ctx, grn_id id)
|
|
{
|
|
grn_plugin *plugin;
|
|
int size;
|
|
|
|
CRITICAL_SECTION_ENTER(grn_plugins_lock);
|
|
size = grn_hash_get_value(&grn_plugins_ctx, grn_plugins, id, &plugin);
|
|
CRITICAL_SECTION_LEAVE(grn_plugins_lock);
|
|
|
|
if (size == 0) {
|
|
return GRN_INVALID_ARGUMENT;
|
|
}
|
|
|
|
#ifdef GRN_WITH_MRUBY
|
|
if (!plugin->dl) {
|
|
return grn_plugin_call_register_mrb(ctx, id, plugin);
|
|
}
|
|
#endif /* GRN_WITH_MRUBY */
|
|
|
|
if (plugin->register_func) {
|
|
return plugin->register_func(ctx);
|
|
}
|
|
|
|
return GRN_SUCCESS;
|
|
}
|
|
|
|
static grn_rc
|
|
grn_plugin_call_fin(grn_ctx *ctx, grn_id id)
|
|
{
|
|
grn_plugin *plugin;
|
|
int size;
|
|
|
|
size = grn_hash_get_value(&grn_plugins_ctx, grn_plugins, id, &plugin);
|
|
if (size == 0) {
|
|
return GRN_INVALID_ARGUMENT;
|
|
}
|
|
|
|
if (plugin->fin_func) {
|
|
return plugin->fin_func(ctx);
|
|
}
|
|
|
|
return GRN_SUCCESS;
|
|
}
|
|
|
|
static grn_rc
|
|
grn_plugin_initialize(grn_ctx *ctx, grn_plugin *plugin,
|
|
grn_dl dl, grn_id id, const char *path)
|
|
{
|
|
plugin->dl = dl;
|
|
|
|
#define GET_SYMBOL(type) do { \
|
|
grn_dl_clear_error(); \
|
|
plugin->type ## _func = grn_dl_sym(dl, GRN_PLUGIN_FUNC_PREFIX #type); \
|
|
if (!plugin->type ## _func) { \
|
|
const char *label; \
|
|
label = grn_dl_sym_error_label(); \
|
|
SERR("%s", label); \
|
|
} \
|
|
} while (0)
|
|
|
|
GET_SYMBOL(init);
|
|
GET_SYMBOL(register);
|
|
GET_SYMBOL(fin);
|
|
|
|
#undef GET_SYMBOL
|
|
|
|
if (!plugin->init_func || !plugin->register_func || !plugin->fin_func) {
|
|
ERR(GRN_INVALID_FORMAT,
|
|
"init func (%s) %sfound, "
|
|
"register func (%s) %sfound and "
|
|
"fin func (%s) %sfound",
|
|
GRN_PLUGIN_FUNC_PREFIX "init", plugin->init_func ? "" : "not ",
|
|
GRN_PLUGIN_FUNC_PREFIX "register", plugin->register_func ? "" : "not ",
|
|
GRN_PLUGIN_FUNC_PREFIX "fin", plugin->fin_func ? "" : "not ");
|
|
}
|
|
|
|
if (!ctx->rc) {
|
|
ctx->impl->plugin_path = path;
|
|
grn_plugin_call_init(ctx, id);
|
|
ctx->impl->plugin_path = NULL;
|
|
}
|
|
|
|
return ctx->rc;
|
|
}
|
|
|
|
#ifdef GRN_WITH_MRUBY
|
|
static grn_id
|
|
grn_plugin_open_mrb(grn_ctx *ctx, const char *filename, size_t filename_size)
|
|
{
|
|
grn_ctx *plugins_ctx = &grn_plugins_ctx;
|
|
grn_id id = GRN_ID_NIL;
|
|
grn_plugin **plugin = NULL;
|
|
|
|
grn_ctx_impl_mrb_ensure_init(ctx);
|
|
if (ctx->rc != GRN_SUCCESS) {
|
|
return GRN_ID_NIL;
|
|
}
|
|
|
|
if (!ctx->impl->mrb.state) {
|
|
ERR(GRN_FUNCTION_NOT_IMPLEMENTED, "mruby support isn't enabled");
|
|
return GRN_ID_NIL;
|
|
}
|
|
|
|
id = grn_hash_add(plugins_ctx, grn_plugins, filename, filename_size,
|
|
(void **)&plugin, NULL);
|
|
if (!id) {
|
|
return id;
|
|
}
|
|
|
|
{
|
|
grn_ctx *ctx = plugins_ctx;
|
|
*plugin = GRN_MALLOCN(grn_plugin, 1);
|
|
}
|
|
if (!*plugin) {
|
|
grn_hash_delete_by_id(plugins_ctx, grn_plugins, id, NULL);
|
|
return GRN_ID_NIL;
|
|
}
|
|
|
|
grn_memcpy((*plugin)->path, filename, filename_size);
|
|
(*plugin)->dl = NULL;
|
|
(*plugin)->init_func = NULL;
|
|
(*plugin)->register_func = NULL;
|
|
(*plugin)->fin_func = NULL;
|
|
(*plugin)->refcount = 1;
|
|
|
|
return id;
|
|
}
|
|
#endif /* GRN_WITH_MRUBY */
|
|
|
|
grn_id
|
|
grn_plugin_open(grn_ctx *ctx, const char *filename)
|
|
{
|
|
grn_ctx *plugins_ctx = &grn_plugins_ctx;
|
|
grn_id id = GRN_ID_NIL;
|
|
grn_dl dl;
|
|
grn_plugin **plugin = NULL;
|
|
size_t filename_size;
|
|
|
|
filename_size = GRN_PLUGIN_KEY_SIZE(filename);
|
|
|
|
CRITICAL_SECTION_ENTER(grn_plugins_lock);
|
|
if ((id = grn_hash_get(plugins_ctx, grn_plugins, filename, filename_size,
|
|
(void **)&plugin))) {
|
|
(*plugin)->refcount++;
|
|
goto exit;
|
|
}
|
|
|
|
#ifdef GRN_WITH_MRUBY
|
|
{
|
|
const char *mrb_suffix;
|
|
mrb_suffix = grn_plugin_get_ruby_suffix();
|
|
if (filename_size > strlen(mrb_suffix) &&
|
|
strcmp(filename + (strlen(filename) - strlen(mrb_suffix)),
|
|
mrb_suffix) == 0) {
|
|
id = grn_plugin_open_mrb(ctx, filename, filename_size);
|
|
goto exit;
|
|
}
|
|
}
|
|
#endif /* GRN_WITH_MRUBY */
|
|
|
|
if ((dl = grn_dl_open(filename))) {
|
|
if ((id = grn_hash_add(plugins_ctx, grn_plugins, filename, filename_size,
|
|
(void **)&plugin, NULL))) {
|
|
{
|
|
grn_ctx *ctx = plugins_ctx;
|
|
*plugin = GRN_MALLOCN(grn_plugin, 1);
|
|
}
|
|
if (*plugin) {
|
|
grn_memcpy((*plugin)->path, filename, filename_size);
|
|
if (grn_plugin_initialize(ctx, *plugin, dl, id, filename)) {
|
|
{
|
|
grn_ctx *ctx = plugins_ctx;
|
|
GRN_FREE(*plugin);
|
|
}
|
|
*plugin = NULL;
|
|
}
|
|
}
|
|
if (!*plugin) {
|
|
grn_hash_delete_by_id(plugins_ctx, grn_plugins, id, NULL);
|
|
if (grn_dl_close(dl)) {
|
|
/* Now, __FILE__ set in plugin is invalid. */
|
|
ctx->errline = 0;
|
|
ctx->errfile = NULL;
|
|
} else {
|
|
const char *label;
|
|
label = grn_dl_close_error_label();
|
|
SERR("%s", label);
|
|
}
|
|
id = GRN_ID_NIL;
|
|
} else {
|
|
(*plugin)->refcount = 1;
|
|
}
|
|
} else {
|
|
if (!grn_dl_close(dl)) {
|
|
const char *label;
|
|
label = grn_dl_close_error_label();
|
|
SERR("%s", label);
|
|
}
|
|
}
|
|
} else {
|
|
const char *label;
|
|
label = grn_dl_open_error_label();
|
|
SERR("%s", label);
|
|
}
|
|
|
|
exit:
|
|
CRITICAL_SECTION_LEAVE(grn_plugins_lock);
|
|
|
|
return id;
|
|
}
|
|
|
|
grn_rc
|
|
grn_plugin_close(grn_ctx *ctx, grn_id id)
|
|
{
|
|
grn_ctx *plugins_ctx = &grn_plugins_ctx;
|
|
grn_rc rc;
|
|
grn_plugin *plugin;
|
|
|
|
if (id == GRN_ID_NIL) {
|
|
return GRN_INVALID_ARGUMENT;
|
|
}
|
|
|
|
CRITICAL_SECTION_ENTER(grn_plugins_lock);
|
|
if (!grn_hash_get_value(plugins_ctx, grn_plugins, id, &plugin)) {
|
|
rc = GRN_INVALID_ARGUMENT;
|
|
goto exit;
|
|
}
|
|
if (--plugin->refcount) {
|
|
rc = GRN_SUCCESS;
|
|
goto exit;
|
|
}
|
|
if (plugin->dl) {
|
|
grn_plugin_call_fin(ctx, id);
|
|
if (!grn_dl_close(plugin->dl)) {
|
|
const char *label;
|
|
label = grn_dl_close_error_label();
|
|
SERR("%s", label);
|
|
}
|
|
}
|
|
{
|
|
grn_ctx *ctx = plugins_ctx;
|
|
GRN_FREE(plugin);
|
|
}
|
|
rc = grn_hash_delete_by_id(plugins_ctx, grn_plugins, id, NULL);
|
|
|
|
exit:
|
|
CRITICAL_SECTION_LEAVE(grn_plugins_lock);
|
|
|
|
return rc;
|
|
}
|
|
|
|
void *
|
|
grn_plugin_sym(grn_ctx *ctx, grn_id id, const char *symbol)
|
|
{
|
|
grn_plugin *plugin;
|
|
grn_dl_symbol func;
|
|
|
|
if (id == GRN_ID_NIL) {
|
|
return NULL;
|
|
}
|
|
|
|
CRITICAL_SECTION_ENTER(grn_plugins_lock);
|
|
if (!grn_hash_get_value(&grn_plugins_ctx, grn_plugins, id, &plugin)) {
|
|
func = NULL;
|
|
goto exit;
|
|
}
|
|
grn_dl_clear_error();
|
|
if (!(func = grn_dl_sym(plugin->dl, symbol))) {
|
|
const char *label;
|
|
label = grn_dl_sym_error_label();
|
|
SERR("%s", label);
|
|
}
|
|
|
|
exit:
|
|
CRITICAL_SECTION_LEAVE(grn_plugins_lock);
|
|
|
|
return func;
|
|
}
|
|
|
|
grn_rc
|
|
grn_plugins_init(void)
|
|
{
|
|
CRITICAL_SECTION_INIT(grn_plugins_lock);
|
|
grn_ctx_init(&grn_plugins_ctx, 0);
|
|
grn_plugins = grn_hash_create(&grn_plugins_ctx, NULL,
|
|
PATH_MAX, sizeof(grn_plugin *),
|
|
GRN_OBJ_KEY_VAR_SIZE);
|
|
if (!grn_plugins) {
|
|
grn_ctx_fin(&grn_plugins_ctx);
|
|
return GRN_NO_MEMORY_AVAILABLE;
|
|
}
|
|
return GRN_SUCCESS;
|
|
}
|
|
|
|
grn_rc
|
|
grn_plugins_fin(void)
|
|
{
|
|
grn_rc rc;
|
|
if (!grn_plugins) { return GRN_INVALID_ARGUMENT; }
|
|
GRN_HASH_EACH(&grn_plugins_ctx, grn_plugins, id, NULL, NULL, NULL, {
|
|
grn_plugin_close(&grn_plugins_ctx, id);
|
|
});
|
|
rc = grn_hash_close(&grn_plugins_ctx, grn_plugins);
|
|
grn_ctx_fin(&grn_plugins_ctx);
|
|
CRITICAL_SECTION_FIN(grn_plugins_lock);
|
|
return rc;
|
|
}
|
|
|
|
const char *
|
|
grn_plugin_get_suffix(void)
|
|
{
|
|
return GRN_PLUGIN_SUFFIX;
|
|
}
|
|
|
|
const char *
|
|
grn_plugin_get_ruby_suffix(void)
|
|
{
|
|
return ".rb";
|
|
}
|
|
|
|
grn_rc
|
|
grn_plugin_register_by_path(grn_ctx *ctx, const char *path)
|
|
{
|
|
grn_obj *db;
|
|
if (!ctx || !ctx->impl || !(db = ctx->impl->db)) {
|
|
ERR(GRN_INVALID_ARGUMENT, "db not initialized");
|
|
return ctx->rc;
|
|
}
|
|
GRN_API_ENTER;
|
|
if (GRN_DB_P(db)) {
|
|
grn_id id;
|
|
id = grn_plugin_open(ctx, path);
|
|
if (id) {
|
|
ctx->impl->plugin_path = path;
|
|
ctx->rc = grn_plugin_call_register(ctx, id);
|
|
ctx->impl->plugin_path = NULL;
|
|
grn_plugin_close(ctx, id);
|
|
}
|
|
} else {
|
|
ERR(GRN_INVALID_ARGUMENT, "invalid db assigned");
|
|
}
|
|
GRN_API_RETURN(ctx->rc);
|
|
}
|
|
|
|
#ifdef WIN32
|
|
static char *windows_plugins_dir = NULL;
|
|
static char windows_plugins_dir_buffer[PATH_MAX];
|
|
static const char *
|
|
grn_plugin_get_default_system_plugins_dir(void)
|
|
{
|
|
if (!windows_plugins_dir) {
|
|
const char *base_dir;
|
|
const char *relative_path = GRN_RELATIVE_PLUGINS_DIR;
|
|
size_t base_dir_length;
|
|
|
|
base_dir = grn_windows_base_dir();
|
|
base_dir_length = strlen(base_dir);
|
|
grn_strcpy(windows_plugins_dir_buffer, PATH_MAX, base_dir);
|
|
grn_strcat(windows_plugins_dir_buffer, PATH_MAX, "/");
|
|
grn_strcat(windows_plugins_dir_buffer, PATH_MAX, relative_path);
|
|
windows_plugins_dir = windows_plugins_dir_buffer;
|
|
}
|
|
return windows_plugins_dir;
|
|
}
|
|
|
|
#else /* WIN32 */
|
|
static const char *
|
|
grn_plugin_get_default_system_plugins_dir(void)
|
|
{
|
|
return GRN_PLUGINS_DIR;
|
|
}
|
|
#endif /* WIN32 */
|
|
|
|
const char *
|
|
grn_plugin_get_system_plugins_dir(void)
|
|
{
|
|
if (grn_plugins_dir[0]) {
|
|
return grn_plugins_dir;
|
|
} else {
|
|
return grn_plugin_get_default_system_plugins_dir();
|
|
}
|
|
}
|
|
|
|
static char *
|
|
grn_plugin_find_path_raw(grn_ctx *ctx, const char *path)
|
|
{
|
|
struct stat path_stat;
|
|
|
|
if (stat(path, &path_stat) != 0) {
|
|
return NULL;
|
|
}
|
|
|
|
if (!S_ISREG(path_stat.st_mode)) {
|
|
return NULL;
|
|
}
|
|
|
|
return GRN_STRDUP(path);
|
|
}
|
|
|
|
#ifdef GRN_WITH_MRUBY
|
|
static char *
|
|
grn_plugin_find_path_mrb(grn_ctx *ctx, const char *path, size_t path_len)
|
|
{
|
|
char mrb_path[PATH_MAX];
|
|
const char *mrb_suffix;
|
|
size_t mrb_path_len;
|
|
|
|
grn_ctx_impl_mrb_ensure_init(ctx);
|
|
if (ctx->rc != GRN_SUCCESS) {
|
|
return NULL;
|
|
}
|
|
|
|
if (!ctx->impl->mrb.state) {
|
|
return NULL;
|
|
}
|
|
|
|
mrb_suffix = grn_plugin_get_ruby_suffix();
|
|
mrb_path_len = path_len + strlen(mrb_suffix);
|
|
if (mrb_path_len >= PATH_MAX) {
|
|
ERR(GRN_FILENAME_TOO_LONG,
|
|
"too long plugin path: <%s%s>",
|
|
path, mrb_suffix);
|
|
return NULL;
|
|
}
|
|
|
|
grn_strcpy(mrb_path, PATH_MAX, path);
|
|
grn_strcat(mrb_path, PATH_MAX, mrb_suffix);
|
|
return grn_plugin_find_path_raw(ctx, mrb_path);
|
|
}
|
|
#else /* GRN_WITH_MRUBY */
|
|
static char *
|
|
grn_plugin_find_path_mrb(grn_ctx *ctx, const char *path, size_t path_len)
|
|
{
|
|
return NULL;
|
|
}
|
|
#endif /* GRN_WITH_MRUBY */
|
|
|
|
static char *
|
|
grn_plugin_find_path_so(grn_ctx *ctx, const char *path, size_t path_len)
|
|
{
|
|
char so_path[PATH_MAX];
|
|
const char *so_suffix;
|
|
size_t so_path_len;
|
|
|
|
so_suffix = grn_plugin_get_suffix();
|
|
so_path_len = path_len + strlen(so_suffix);
|
|
if (so_path_len >= PATH_MAX) {
|
|
ERR(GRN_FILENAME_TOO_LONG,
|
|
"too long plugin path: <%s%s>",
|
|
path, so_suffix);
|
|
return NULL;
|
|
}
|
|
|
|
grn_strcpy(so_path, PATH_MAX, path);
|
|
grn_strcat(so_path, PATH_MAX, so_suffix);
|
|
return grn_plugin_find_path_raw(ctx, so_path);
|
|
}
|
|
|
|
static char *
|
|
grn_plugin_find_path_libs_so(grn_ctx *ctx, const char *path, size_t path_len)
|
|
{
|
|
char libs_so_path[PATH_MAX];
|
|
const char *base_name;
|
|
const char *so_suffix;
|
|
const char *libs_path = "/.libs";
|
|
size_t libs_so_path_len;
|
|
|
|
base_name = strrchr(path, '/');
|
|
if (!base_name) {
|
|
return NULL;
|
|
}
|
|
|
|
so_suffix = grn_plugin_get_suffix();
|
|
libs_so_path_len =
|
|
base_name - path +
|
|
strlen(libs_path) +
|
|
strlen(base_name) +
|
|
strlen(so_suffix);
|
|
if (libs_so_path_len >= PATH_MAX) {
|
|
ERR(GRN_FILENAME_TOO_LONG,
|
|
"too long plugin path: <%.*s/.libs%s%s>",
|
|
(int)(base_name - path), path, base_name, so_suffix);
|
|
return NULL;
|
|
}
|
|
|
|
libs_so_path[0] = '\0';
|
|
grn_strncat(libs_so_path, PATH_MAX, path, base_name - path);
|
|
grn_strcat(libs_so_path, PATH_MAX, libs_path);
|
|
grn_strcat(libs_so_path, PATH_MAX, base_name);
|
|
grn_strcat(libs_so_path, PATH_MAX, so_suffix);
|
|
return grn_plugin_find_path_raw(ctx, libs_so_path);
|
|
}
|
|
|
|
char *
|
|
grn_plugin_find_path(grn_ctx *ctx, const char *name)
|
|
{
|
|
const char *plugins_dir;
|
|
char dir_last_char;
|
|
char path[PATH_MAX];
|
|
int name_length, max_name_length;
|
|
char *found_path = NULL;
|
|
size_t path_len;
|
|
|
|
GRN_API_ENTER;
|
|
if (name[0] == '/') {
|
|
path[0] = '\0';
|
|
} else {
|
|
plugins_dir = grn_plugin_get_system_plugins_dir();
|
|
grn_strcpy(path, PATH_MAX, plugins_dir);
|
|
|
|
dir_last_char = plugins_dir[strlen(path) - 1];
|
|
if (dir_last_char != '/') {
|
|
grn_strcat(path, PATH_MAX, "/");
|
|
}
|
|
}
|
|
|
|
name_length = strlen(name);
|
|
max_name_length = PATH_MAX - strlen(path) - 1;
|
|
if (name_length > max_name_length) {
|
|
ERR(GRN_INVALID_ARGUMENT,
|
|
"plugin name is too long: %d (max: %d) <%s%s>",
|
|
name_length, max_name_length,
|
|
path, name);
|
|
goto exit;
|
|
}
|
|
grn_strcat(path, PATH_MAX, name);
|
|
|
|
found_path = grn_plugin_find_path_raw(ctx, path);
|
|
if (found_path) {
|
|
goto exit;
|
|
}
|
|
|
|
path_len = strlen(path);
|
|
|
|
found_path = grn_plugin_find_path_so(ctx, path, path_len);
|
|
if (found_path) {
|
|
goto exit;
|
|
}
|
|
if (ctx->rc) {
|
|
goto exit;
|
|
}
|
|
|
|
found_path = grn_plugin_find_path_libs_so(ctx, path, path_len);
|
|
if (found_path) {
|
|
goto exit;
|
|
}
|
|
if (ctx->rc) {
|
|
goto exit;
|
|
}
|
|
|
|
found_path = grn_plugin_find_path_mrb(ctx, path, path_len);
|
|
if (found_path) {
|
|
goto exit;
|
|
}
|
|
if (ctx->rc) {
|
|
goto exit;
|
|
}
|
|
|
|
exit :
|
|
GRN_API_RETURN(found_path);
|
|
}
|
|
|
|
static void
|
|
grn_plugin_set_name_resolve_error(grn_ctx *ctx, const char *name,
|
|
const char *tag)
|
|
{
|
|
const char *prefix, *prefix_separator, *suffix;
|
|
|
|
if (name[0] == '/') {
|
|
prefix = "";
|
|
prefix_separator = "";
|
|
suffix = "";
|
|
} else {
|
|
prefix = grn_plugin_get_system_plugins_dir();
|
|
if (prefix[strlen(prefix) - 1] != '/') {
|
|
prefix_separator = "/";
|
|
} else {
|
|
prefix_separator = "";
|
|
}
|
|
suffix = grn_plugin_get_suffix();
|
|
}
|
|
ERR(GRN_NO_SUCH_FILE_OR_DIRECTORY,
|
|
"%s cannot find plugin file: <%s%s%s%s>",
|
|
tag, prefix, prefix_separator, name, suffix);
|
|
}
|
|
|
|
grn_rc
|
|
grn_plugin_register(grn_ctx *ctx, const char *name)
|
|
{
|
|
grn_rc rc;
|
|
char *path;
|
|
|
|
GRN_API_ENTER;
|
|
path = grn_plugin_find_path(ctx, name);
|
|
if (path) {
|
|
rc = grn_plugin_register_by_path(ctx, path);
|
|
GRN_FREE(path);
|
|
} else {
|
|
if (ctx->rc == GRN_SUCCESS) {
|
|
grn_plugin_set_name_resolve_error(ctx, name, "[plugin][register]");
|
|
}
|
|
rc = ctx->rc;
|
|
}
|
|
GRN_API_RETURN(rc);
|
|
}
|
|
|
|
grn_rc
|
|
grn_plugin_unregister_by_path(grn_ctx *ctx, const char *path)
|
|
{
|
|
grn_obj *db;
|
|
grn_id plugin_id;
|
|
|
|
if (!ctx || !ctx->impl) {
|
|
ERR(GRN_INVALID_ARGUMENT, "[plugin][unregister] ctx isn't initialized");
|
|
return ctx->rc;
|
|
}
|
|
|
|
db = ctx->impl->db;
|
|
if (!db) {
|
|
ERR(GRN_INVALID_ARGUMENT, "[plugin][unregister] DB isn't initialized");
|
|
return ctx->rc;
|
|
}
|
|
|
|
GRN_API_ENTER;
|
|
|
|
CRITICAL_SECTION_ENTER(grn_plugins_lock);
|
|
plugin_id = grn_hash_get(&grn_plugins_ctx, grn_plugins,
|
|
path, GRN_PLUGIN_KEY_SIZE(path),
|
|
NULL);
|
|
CRITICAL_SECTION_LEAVE(grn_plugins_lock);
|
|
|
|
if (plugin_id == GRN_ID_NIL) {
|
|
GRN_API_RETURN(ctx->rc);
|
|
}
|
|
|
|
{
|
|
grn_table_cursor *cursor;
|
|
grn_id id;
|
|
|
|
cursor = grn_table_cursor_open(ctx, db,
|
|
NULL, 0,
|
|
NULL, 0,
|
|
0, -1, GRN_CURSOR_BY_ID);
|
|
if (!cursor) {
|
|
GRN_API_RETURN(ctx->rc);
|
|
}
|
|
|
|
while ((id = grn_table_cursor_next(ctx, cursor))) {
|
|
grn_obj *obj;
|
|
obj = grn_ctx_at(ctx, id);
|
|
if (!obj) {
|
|
continue;
|
|
}
|
|
if (obj->header.type == GRN_PROC && DB_OBJ(obj)->range == plugin_id) {
|
|
grn_obj_remove(ctx, obj);
|
|
} else {
|
|
grn_obj_unlink(ctx, obj);
|
|
}
|
|
}
|
|
grn_table_cursor_close(ctx, cursor);
|
|
}
|
|
|
|
GRN_API_RETURN(ctx->rc);
|
|
}
|
|
|
|
grn_rc
|
|
grn_plugin_unregister(grn_ctx *ctx, const char *name)
|
|
{
|
|
grn_rc rc;
|
|
char *path;
|
|
|
|
GRN_API_ENTER;
|
|
path = grn_plugin_find_path(ctx, name);
|
|
if (path) {
|
|
rc = grn_plugin_unregister_by_path(ctx, path);
|
|
GRN_FREE(path);
|
|
} else {
|
|
if (ctx->rc == GRN_SUCCESS) {
|
|
grn_plugin_set_name_resolve_error(ctx, name, "[plugin][unregister]");
|
|
}
|
|
rc = ctx->rc;
|
|
}
|
|
GRN_API_RETURN(rc);
|
|
}
|
|
|
|
void
|
|
grn_plugin_ensure_registered(grn_ctx *ctx, grn_obj *proc)
|
|
{
|
|
#ifdef GRN_WITH_MRUBY
|
|
grn_id plugin_id;
|
|
grn_plugin *plugin = NULL;
|
|
|
|
if (!(proc->header.flags & GRN_OBJ_CUSTOM_NAME)) {
|
|
return;
|
|
}
|
|
|
|
plugin_id = DB_OBJ(proc)->range;
|
|
CRITICAL_SECTION_ENTER(grn_plugins_lock);
|
|
{
|
|
const char *value;
|
|
value = grn_hash_get_value_(&grn_plugins_ctx, grn_plugins, plugin_id, NULL);
|
|
if (value) {
|
|
plugin = *((grn_plugin **)value);
|
|
}
|
|
}
|
|
CRITICAL_SECTION_LEAVE(grn_plugins_lock);
|
|
|
|
if (!plugin) {
|
|
return;
|
|
}
|
|
|
|
if (plugin->dl) {
|
|
return;
|
|
}
|
|
|
|
grn_ctx_impl_mrb_ensure_init(ctx);
|
|
if (ctx->rc != GRN_SUCCESS) {
|
|
return;
|
|
}
|
|
|
|
if (!ctx->impl->mrb.state) {
|
|
return;
|
|
}
|
|
|
|
{
|
|
grn_id id;
|
|
int added;
|
|
id = DB_OBJ(proc)->id;
|
|
grn_hash_add(ctx, ctx->impl->mrb.checked_procs,
|
|
&id, sizeof(grn_id), NULL, &added);
|
|
if (!added) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
ctx->impl->plugin_path = plugin->path;
|
|
grn_plugin_call_register_mrb(ctx, plugin_id, plugin);
|
|
ctx->impl->plugin_path = NULL;
|
|
#endif /* GRN_WITH_MRUBY */
|
|
}
|
|
|
|
grn_rc
|
|
grn_plugin_get_names(grn_ctx *ctx, grn_obj *names)
|
|
{
|
|
grn_hash *processed_paths;
|
|
const char *system_plugins_dir;
|
|
const char *native_plugin_suffix;
|
|
const char *ruby_plugin_suffix;
|
|
grn_bool is_close_opened_object_mode = GRN_FALSE;
|
|
|
|
GRN_API_ENTER;
|
|
|
|
if (ctx->rc) {
|
|
GRN_API_RETURN(ctx->rc);
|
|
}
|
|
|
|
if (grn_thread_get_limit() == 1) {
|
|
is_close_opened_object_mode = GRN_TRUE;
|
|
}
|
|
|
|
processed_paths = grn_hash_create(ctx, NULL, GRN_TABLE_MAX_KEY_SIZE, 0,
|
|
GRN_OBJ_TABLE_HASH_KEY |
|
|
GRN_OBJ_KEY_VAR_SIZE);
|
|
if (!processed_paths) {
|
|
GRN_API_RETURN(ctx->rc);
|
|
}
|
|
|
|
system_plugins_dir = grn_plugin_get_system_plugins_dir();
|
|
native_plugin_suffix = grn_plugin_get_suffix();
|
|
ruby_plugin_suffix = grn_plugin_get_ruby_suffix();
|
|
|
|
GRN_TABLE_EACH_BEGIN_FLAGS(ctx, grn_ctx_db(ctx), cursor, id,
|
|
GRN_CURSOR_BY_ID | GRN_CURSOR_ASCENDING) {
|
|
void *name;
|
|
int name_size;
|
|
grn_obj *object;
|
|
const char *path;
|
|
grn_id processed_path_id;
|
|
|
|
if (grn_id_is_builtin(ctx, id)) {
|
|
continue;
|
|
}
|
|
|
|
name_size = grn_table_cursor_get_key(ctx, cursor, &name);
|
|
if (grn_obj_name_is_column(ctx, name, name_size)) {
|
|
continue;
|
|
}
|
|
|
|
if (is_close_opened_object_mode) {
|
|
grn_ctx_push_temporary_open_space(ctx);
|
|
}
|
|
|
|
object = grn_ctx_at(ctx, id);
|
|
if (!object) {
|
|
ERRCLR(ctx);
|
|
goto next_loop;
|
|
}
|
|
|
|
if (!grn_obj_is_proc(ctx, object)) {
|
|
goto next_loop;
|
|
}
|
|
|
|
path = grn_obj_path(ctx, object);
|
|
if (!path) {
|
|
goto next_loop;
|
|
}
|
|
|
|
processed_path_id = grn_hash_get(ctx, processed_paths,
|
|
path, strlen(path),
|
|
NULL);
|
|
if (processed_path_id != GRN_ID_NIL) {
|
|
goto next_loop;
|
|
}
|
|
|
|
grn_hash_add(ctx, processed_paths,
|
|
path, strlen(path),
|
|
NULL, NULL);
|
|
|
|
{
|
|
const char *relative_path;
|
|
const char *libs_path = "/.libs/";
|
|
const char *start_libs;
|
|
char name[PATH_MAX];
|
|
|
|
name[0] = '\0';
|
|
if (strncmp(path, system_plugins_dir, strlen(system_plugins_dir)) == 0) {
|
|
relative_path = path + strlen(system_plugins_dir);
|
|
} else {
|
|
relative_path = path;
|
|
}
|
|
start_libs = strstr(relative_path, libs_path);
|
|
if (start_libs) {
|
|
grn_strncat(name, PATH_MAX, relative_path, start_libs - relative_path);
|
|
grn_strcat(name, PATH_MAX, "/");
|
|
grn_strcat(name, PATH_MAX, start_libs + strlen(libs_path));
|
|
} else {
|
|
grn_strcat(name, PATH_MAX, relative_path);
|
|
}
|
|
if (strlen(name) > strlen(native_plugin_suffix) &&
|
|
strcmp(name + strlen(name) - strlen(native_plugin_suffix),
|
|
native_plugin_suffix) == 0) {
|
|
name[strlen(name) - strlen(native_plugin_suffix)] = '\0';
|
|
} else if (strlen(name) > strlen(ruby_plugin_suffix) &&
|
|
strcmp(name + strlen(name) - strlen(ruby_plugin_suffix),
|
|
ruby_plugin_suffix) == 0) {
|
|
name[strlen(name) - strlen(ruby_plugin_suffix)] = '\0';
|
|
}
|
|
grn_vector_add_element(ctx, names,
|
|
name, strlen(name),
|
|
0, GRN_DB_TEXT);
|
|
}
|
|
|
|
next_loop :
|
|
if (is_close_opened_object_mode) {
|
|
grn_ctx_pop_temporary_open_space(ctx);
|
|
}
|
|
} GRN_TABLE_EACH_END(ctx, cursor);
|
|
|
|
grn_hash_close(ctx, processed_paths);
|
|
|
|
GRN_API_RETURN(ctx->rc);
|
|
}
|
|
|
|
void *
|
|
grn_plugin_malloc(grn_ctx *ctx, size_t size, const char *file, int line,
|
|
const char *func)
|
|
{
|
|
return grn_malloc(ctx, size, file, line, func);
|
|
}
|
|
|
|
void *
|
|
grn_plugin_calloc(grn_ctx *ctx, size_t size, const char *file, int line,
|
|
const char *func)
|
|
{
|
|
return grn_calloc(ctx, size, file, line, func);
|
|
}
|
|
|
|
void *
|
|
grn_plugin_realloc(grn_ctx *ctx, void *ptr, size_t size,
|
|
const char *file, int line, const char *func)
|
|
{
|
|
return grn_realloc(ctx, ptr, size, file, line, func);
|
|
}
|
|
|
|
void
|
|
grn_plugin_free(grn_ctx *ctx, void *ptr, const char *file, int line,
|
|
const char *func)
|
|
{
|
|
grn_free(ctx, ptr, file, line, func);
|
|
}
|
|
|
|
void
|
|
grn_plugin_set_error(grn_ctx *ctx, grn_log_level level, grn_rc error_code,
|
|
const char *file, int line, const char *func,
|
|
const char *format, ...)
|
|
{
|
|
char old_error_message[GRN_CTX_MSGSIZE];
|
|
|
|
ctx->errlvl = level;
|
|
ctx->rc = error_code;
|
|
ctx->errfile = file;
|
|
ctx->errline = line;
|
|
ctx->errfunc = func;
|
|
|
|
grn_strcpy(old_error_message, GRN_CTX_MSGSIZE, ctx->errbuf);
|
|
|
|
{
|
|
va_list ap;
|
|
va_start(ap, format);
|
|
grn_ctx_logv(ctx, format, ap);
|
|
va_end(ap);
|
|
}
|
|
|
|
if (grn_ctx_impl_should_log(ctx)) {
|
|
grn_ctx_impl_set_current_error_message(ctx);
|
|
if (grn_logger_pass(ctx, level)) {
|
|
char new_error_message[GRN_CTX_MSGSIZE];
|
|
grn_strcpy(new_error_message, GRN_CTX_MSGSIZE, ctx->errbuf);
|
|
grn_strcpy(ctx->errbuf, GRN_CTX_MSGSIZE, old_error_message);
|
|
{
|
|
va_list ap;
|
|
va_start(ap, format);
|
|
grn_logger_putv(ctx, level, file, line, func, format, ap);
|
|
va_end(ap);
|
|
}
|
|
grn_strcpy(ctx->errbuf, GRN_CTX_MSGSIZE, new_error_message);
|
|
}
|
|
if (level <= GRN_LOG_ERROR) {
|
|
grn_plugin_logtrace(ctx, level);
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
grn_plugin_clear_error(grn_ctx *ctx)
|
|
{
|
|
ERRCLR(ctx);
|
|
}
|
|
|
|
void
|
|
grn_plugin_backtrace(grn_ctx *ctx)
|
|
{
|
|
BACKTRACE(ctx);
|
|
}
|
|
|
|
void
|
|
grn_plugin_logtrace(grn_ctx *ctx, grn_log_level level)
|
|
{
|
|
if (level <= GRN_LOG_ERROR) {
|
|
grn_plugin_backtrace(ctx);
|
|
LOGTRACE(ctx, level);
|
|
}
|
|
}
|
|
|
|
struct _grn_plugin_mutex {
|
|
grn_critical_section critical_section;
|
|
};
|
|
|
|
grn_plugin_mutex *
|
|
grn_plugin_mutex_open(grn_ctx *ctx)
|
|
{
|
|
grn_plugin_mutex * const mutex =
|
|
GRN_PLUGIN_MALLOC(ctx, sizeof(grn_plugin_mutex));
|
|
if (mutex != NULL) {
|
|
CRITICAL_SECTION_INIT(mutex->critical_section);
|
|
}
|
|
return mutex;
|
|
}
|
|
|
|
grn_plugin_mutex *
|
|
grn_plugin_mutex_create(grn_ctx *ctx)
|
|
{
|
|
return grn_plugin_mutex_open(ctx);
|
|
}
|
|
|
|
void
|
|
grn_plugin_mutex_close(grn_ctx *ctx, grn_plugin_mutex *mutex)
|
|
{
|
|
if (mutex != NULL) {
|
|
CRITICAL_SECTION_FIN(mutex->critical_section);
|
|
GRN_PLUGIN_FREE(ctx, mutex);
|
|
}
|
|
}
|
|
|
|
void
|
|
grn_plugin_mutex_destroy(grn_ctx *ctx, grn_plugin_mutex *mutex)
|
|
{
|
|
grn_plugin_mutex_close(ctx, mutex);
|
|
}
|
|
|
|
void
|
|
grn_plugin_mutex_lock(grn_ctx *ctx, grn_plugin_mutex *mutex)
|
|
{
|
|
if (mutex != NULL) {
|
|
CRITICAL_SECTION_ENTER(mutex->critical_section);
|
|
}
|
|
}
|
|
|
|
void
|
|
grn_plugin_mutex_unlock(grn_ctx *ctx, grn_plugin_mutex *mutex)
|
|
{
|
|
if (mutex != NULL) {
|
|
CRITICAL_SECTION_LEAVE(mutex->critical_section);
|
|
}
|
|
}
|
|
|
|
grn_obj *
|
|
grn_plugin_proc_alloc(grn_ctx *ctx, grn_user_data *user_data,
|
|
grn_id domain, unsigned char flags)
|
|
{
|
|
return grn_proc_alloc(ctx, user_data, domain, flags);
|
|
}
|
|
|
|
grn_obj *
|
|
grn_plugin_proc_get_vars(grn_ctx *ctx, grn_user_data *user_data)
|
|
{
|
|
return grn_proc_get_vars(ctx, user_data);
|
|
}
|
|
|
|
grn_obj *
|
|
grn_plugin_proc_get_var(grn_ctx *ctx, grn_user_data *user_data,
|
|
const char *name, int name_size)
|
|
{
|
|
name_size = compute_name_size(name, name_size);
|
|
return grn_proc_get_var(ctx, user_data, name, name_size);
|
|
}
|
|
|
|
grn_bool
|
|
grn_plugin_proc_get_var_bool(grn_ctx *ctx,
|
|
grn_user_data *user_data,
|
|
const char *name,
|
|
int name_size,
|
|
grn_bool default_value)
|
|
{
|
|
grn_obj *var;
|
|
|
|
var = grn_plugin_proc_get_var(ctx, user_data, name, name_size);
|
|
return grn_proc_option_value_bool(ctx, var, default_value);
|
|
}
|
|
|
|
int32_t
|
|
grn_plugin_proc_get_var_int32(grn_ctx *ctx,
|
|
grn_user_data *user_data,
|
|
const char *name,
|
|
int name_size,
|
|
int32_t default_value)
|
|
{
|
|
grn_obj *var;
|
|
|
|
var = grn_plugin_proc_get_var(ctx, user_data, name, name_size);
|
|
return grn_proc_option_value_int32(ctx, var, default_value);
|
|
}
|
|
|
|
const char *
|
|
grn_plugin_proc_get_var_string(grn_ctx *ctx,
|
|
grn_user_data *user_data,
|
|
const char *name,
|
|
int name_size,
|
|
size_t *size)
|
|
{
|
|
grn_obj *var;
|
|
|
|
var = grn_plugin_proc_get_var(ctx, user_data, name, name_size);
|
|
return grn_proc_option_value_string(ctx, var, size);
|
|
}
|
|
|
|
grn_content_type
|
|
grn_plugin_proc_get_var_content_type(grn_ctx *ctx,
|
|
grn_user_data *user_data,
|
|
const char *name,
|
|
int name_size,
|
|
grn_content_type default_value)
|
|
{
|
|
grn_obj *var;
|
|
|
|
var = grn_plugin_proc_get_var(ctx, user_data, name, name_size);
|
|
return grn_proc_option_value_content_type(ctx, var, default_value);
|
|
}
|
|
|
|
grn_obj *
|
|
grn_plugin_proc_get_var_by_offset(grn_ctx *ctx, grn_user_data *user_data,
|
|
unsigned int offset)
|
|
{
|
|
return grn_proc_get_var_by_offset(ctx, user_data, offset);
|
|
}
|
|
|
|
grn_obj *
|
|
grn_plugin_proc_get_caller(grn_ctx *ctx, grn_user_data *user_data)
|
|
{
|
|
grn_obj *caller = NULL;
|
|
GRN_API_ENTER;
|
|
grn_proc_get_info(ctx, user_data, NULL, NULL, &caller);
|
|
GRN_API_RETURN(caller);
|
|
}
|
|
|
|
const char *
|
|
grn_plugin_win32_base_dir(void)
|
|
{
|
|
return grn_plugin_windows_base_dir();
|
|
}
|
|
|
|
const char *
|
|
grn_plugin_windows_base_dir(void)
|
|
{
|
|
#ifdef WIN32
|
|
return grn_windows_base_dir();
|
|
#else /* WIN32 */
|
|
return NULL;
|
|
#endif /* WIN32 */
|
|
}
|
|
|
|
/*
|
|
grn_plugin_charlen() takes the length of a string, unlike grn_charlen_().
|
|
*/
|
|
int
|
|
grn_plugin_charlen(grn_ctx *ctx, const char *str_ptr,
|
|
unsigned int str_length, grn_encoding encoding)
|
|
{
|
|
return grn_charlen_(ctx, str_ptr, str_ptr + str_length, encoding);
|
|
}
|
|
|
|
/*
|
|
grn_plugin_isspace() takes the length of a string, unlike grn_isspace().
|
|
*/
|
|
int
|
|
grn_plugin_isspace(grn_ctx *ctx, const char *str_ptr,
|
|
unsigned int str_length, grn_encoding encoding)
|
|
{
|
|
if ((str_ptr == NULL) || (str_length == 0)) {
|
|
return 0;
|
|
}
|
|
switch ((unsigned char)str_ptr[0]) {
|
|
case ' ' :
|
|
case '\f' :
|
|
case '\n' :
|
|
case '\r' :
|
|
case '\t' :
|
|
case '\v' :
|
|
return 1;
|
|
case 0x81 :
|
|
if ((encoding == GRN_ENC_SJIS) && (str_length >= 2) &&
|
|
((unsigned char)str_ptr[1] == 0x40)) {
|
|
return 2;
|
|
}
|
|
break;
|
|
case 0xA1 :
|
|
if ((encoding == GRN_ENC_EUC_JP) && (str_length >= 2) &&
|
|
((unsigned char)str_ptr[1] == 0xA1)) {
|
|
return 2;
|
|
}
|
|
break;
|
|
case 0xE3 :
|
|
if ((encoding == GRN_ENC_UTF8) && (str_length >= 3) &&
|
|
((unsigned char)str_ptr[1] == 0x80) &&
|
|
((unsigned char)str_ptr[2] == 0x80)) {
|
|
return 3;
|
|
}
|
|
break;
|
|
default :
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
grn_rc
|
|
grn_plugin_expr_var_init(grn_ctx *ctx,
|
|
grn_expr_var *var,
|
|
const char *name,
|
|
int name_size)
|
|
{
|
|
var->name = name;
|
|
var->name_size = compute_name_size(name, name_size);
|
|
GRN_TEXT_INIT(&var->value, 0);
|
|
return GRN_SUCCESS;
|
|
}
|
|
|
|
grn_obj *
|
|
grn_plugin_command_create(grn_ctx *ctx,
|
|
const char *name,
|
|
int name_size,
|
|
grn_proc_func func,
|
|
unsigned int n_vars,
|
|
grn_expr_var *vars)
|
|
{
|
|
grn_obj *proc;
|
|
name_size = compute_name_size(name, name_size);
|
|
proc = grn_proc_create(ctx, name, name_size, GRN_PROC_COMMAND,
|
|
func, NULL, NULL, n_vars, vars);
|
|
return proc;
|
|
}
|