1 | /* -*- c-basic-offset: 2 -*- */ |
2 | /* |
3 | Copyright(C) 2012-2017 Brazil |
4 | |
5 | This library is free software; you can redistribute it and/or |
6 | modify it under the terms of the GNU Lesser General Public |
7 | License version 2.1 as published by the Free Software Foundation. |
8 | |
9 | This library is distributed in the hope that it will be useful, |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | Lesser General Public License for more details. |
13 | |
14 | You should have received a copy of the GNU Lesser General Public |
15 | License along with this library; if not, write to the Free Software |
16 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
17 | */ |
18 | #include "grn.h" |
19 | #include "grn_ctx_impl_mrb.h" |
20 | #include "grn_proc.h" |
21 | #include <groonga/plugin.h> |
22 | |
23 | #include <stdarg.h> |
24 | #include <stdio.h> |
25 | #include <string.h> |
26 | |
27 | #include <sys/stat.h> |
28 | #ifdef HAVE_DIRENT_H |
29 | # include <dirent.h> |
30 | #endif /* HAVE_DIRENT_H */ |
31 | |
32 | #ifndef S_ISREG |
33 | # ifdef _S_IFREG |
34 | # define S_ISREG(mode) (mode & _S_IFREG) |
35 | # endif /* _S_IFREG */ |
36 | #endif /* !S_ISREG */ |
37 | |
38 | #include "grn_db.h" |
39 | #include "grn_plugin.h" |
40 | #include "grn_ctx_impl.h" |
41 | #include "grn_util.h" |
42 | |
43 | #ifdef GRN_WITH_MRUBY |
44 | # include <mruby.h> |
45 | #endif /* GRN_WITH_MRUBY */ |
46 | |
47 | static grn_hash *grn_plugins = NULL; |
48 | static grn_critical_section grn_plugins_lock; |
49 | static grn_ctx grn_plugins_ctx; |
50 | |
51 | #ifdef HAVE_DLFCN_H |
52 | # include <dlfcn.h> |
53 | # define grn_dl_open(filename) dlopen(filename, RTLD_LAZY | RTLD_LOCAL) |
54 | # define grn_dl_open_error_label() dlerror() |
55 | # define grn_dl_close(dl) (dlclose(dl) == 0) |
56 | # define grn_dl_close_error_label() dlerror() |
57 | # define grn_dl_sym(dl, symbol) dlsym(dl, symbol) |
58 | # define grn_dl_sym_error_label() dlerror() |
59 | # define grn_dl_clear_error() dlerror() |
60 | #else |
61 | # define grn_dl_open(filename) LoadLibrary(filename) |
62 | # define grn_dl_open_error_label() "LoadLibrary" |
63 | # define grn_dl_close(dl) (FreeLibrary(dl) != 0) |
64 | # define grn_dl_close_error_label() "FreeLibrary" |
65 | # define grn_dl_sym(dl, symbol) ((void *)GetProcAddress(dl, symbol)) |
66 | # define grn_dl_sym_error_label() "GetProcAddress" |
67 | # define grn_dl_clear_error() |
68 | #endif |
69 | |
70 | #define GRN_PLUGIN_KEY_SIZE(filename) (strlen((filename)) + 1) |
71 | |
72 | static char grn_plugins_dir[GRN_ENV_BUFFER_SIZE]; |
73 | |
74 | void |
75 | grn_plugin_init_from_env(void) |
76 | { |
77 | grn_getenv("GRN_PLUGINS_DIR" , |
78 | grn_plugins_dir, |
79 | GRN_ENV_BUFFER_SIZE); |
80 | } |
81 | |
82 | static int |
83 | compute_name_size(const char *name, int name_size) |
84 | { |
85 | if (name_size < 0) { |
86 | if (name) { |
87 | name_size = strlen(name); |
88 | } else { |
89 | name_size = 0; |
90 | } |
91 | } |
92 | return name_size; |
93 | } |
94 | |
95 | grn_id |
96 | grn_plugin_reference(grn_ctx *ctx, const char *filename) |
97 | { |
98 | grn_id id; |
99 | grn_plugin **plugin = NULL; |
100 | |
101 | CRITICAL_SECTION_ENTER(grn_plugins_lock); |
102 | id = grn_hash_get(&grn_plugins_ctx, grn_plugins, |
103 | filename, GRN_PLUGIN_KEY_SIZE(filename), |
104 | (void **)&plugin); |
105 | if (plugin) { |
106 | (*plugin)->refcount++; |
107 | } |
108 | CRITICAL_SECTION_LEAVE(grn_plugins_lock); |
109 | |
110 | return id; |
111 | } |
112 | |
113 | const char * |
114 | grn_plugin_path(grn_ctx *ctx, grn_id id) |
115 | { |
116 | const char *path; |
117 | grn_plugin *plugin; |
118 | int value_size; |
119 | const char *system_plugins_dir; |
120 | size_t system_plugins_dir_size; |
121 | |
122 | if (id == GRN_ID_NIL) { |
123 | return NULL; |
124 | } |
125 | |
126 | CRITICAL_SECTION_ENTER(grn_plugins_lock); |
127 | value_size = grn_hash_get_value(&grn_plugins_ctx, grn_plugins, id, &plugin); |
128 | CRITICAL_SECTION_LEAVE(grn_plugins_lock); |
129 | |
130 | if (!plugin) { |
131 | return NULL; |
132 | } |
133 | |
134 | path = plugin->path; |
135 | system_plugins_dir = grn_plugin_get_system_plugins_dir(); |
136 | system_plugins_dir_size = strlen(system_plugins_dir); |
137 | if (strncmp(system_plugins_dir, path, system_plugins_dir_size) == 0) { |
138 | const char *plugin_name = path + system_plugins_dir_size; |
139 | while (plugin_name[0] == '/') { |
140 | plugin_name++; |
141 | } |
142 | /* TODO: remove suffix too? */ |
143 | return plugin_name; |
144 | } else { |
145 | return path; |
146 | } |
147 | } |
148 | |
149 | #define GRN_PLUGIN_FUNC_PREFIX "grn_plugin_impl_" |
150 | |
151 | static grn_rc |
152 | grn_plugin_call_init(grn_ctx *ctx, grn_id id) |
153 | { |
154 | grn_plugin *plugin; |
155 | int size; |
156 | |
157 | size = grn_hash_get_value(&grn_plugins_ctx, grn_plugins, id, &plugin); |
158 | if (size == 0) { |
159 | return GRN_INVALID_ARGUMENT; |
160 | } |
161 | |
162 | if (plugin->init_func) { |
163 | return plugin->init_func(ctx); |
164 | } |
165 | |
166 | return GRN_SUCCESS; |
167 | } |
168 | |
169 | #ifdef GRN_WITH_MRUBY |
170 | static grn_rc |
171 | grn_plugin_call_register_mrb(grn_ctx *ctx, grn_id id, grn_plugin *plugin) |
172 | { |
173 | grn_mrb_data *data; |
174 | mrb_state *mrb; |
175 | struct RClass *module; |
176 | struct RClass *plugin_loader_class; |
177 | int arena_index; |
178 | |
179 | grn_ctx_impl_mrb_ensure_init(ctx); |
180 | if (ctx->rc != GRN_SUCCESS) { |
181 | return ctx->rc; |
182 | } |
183 | |
184 | data = &(ctx->impl->mrb); |
185 | mrb = data->state; |
186 | module = data->module; |
187 | |
188 | { |
189 | int added; |
190 | grn_hash_add(ctx, ctx->impl->mrb.registered_plugins, |
191 | &id, sizeof(grn_id), NULL, &added); |
192 | if (!added) { |
193 | return ctx->rc; |
194 | } |
195 | } |
196 | |
197 | arena_index = mrb_gc_arena_save(mrb); |
198 | plugin_loader_class = mrb_class_get_under(mrb, module, "PluginLoader" ); |
199 | mrb_funcall(mrb, mrb_obj_value(plugin_loader_class), |
200 | "load_file" , 1, mrb_str_new_cstr(mrb, ctx->impl->plugin_path)); |
201 | mrb_gc_arena_restore(mrb, arena_index); |
202 | return ctx->rc; |
203 | } |
204 | #endif /*GRN_WITH_MRUBY */ |
205 | |
206 | static grn_rc |
207 | grn_plugin_call_register(grn_ctx *ctx, grn_id id) |
208 | { |
209 | grn_plugin *plugin; |
210 | int size; |
211 | |
212 | CRITICAL_SECTION_ENTER(grn_plugins_lock); |
213 | size = grn_hash_get_value(&grn_plugins_ctx, grn_plugins, id, &plugin); |
214 | CRITICAL_SECTION_LEAVE(grn_plugins_lock); |
215 | |
216 | if (size == 0) { |
217 | return GRN_INVALID_ARGUMENT; |
218 | } |
219 | |
220 | #ifdef GRN_WITH_MRUBY |
221 | if (!plugin->dl) { |
222 | return grn_plugin_call_register_mrb(ctx, id, plugin); |
223 | } |
224 | #endif /* GRN_WITH_MRUBY */ |
225 | |
226 | if (plugin->register_func) { |
227 | return plugin->register_func(ctx); |
228 | } |
229 | |
230 | return GRN_SUCCESS; |
231 | } |
232 | |
233 | static grn_rc |
234 | grn_plugin_call_fin(grn_ctx *ctx, grn_id id) |
235 | { |
236 | grn_plugin *plugin; |
237 | int size; |
238 | |
239 | size = grn_hash_get_value(&grn_plugins_ctx, grn_plugins, id, &plugin); |
240 | if (size == 0) { |
241 | return GRN_INVALID_ARGUMENT; |
242 | } |
243 | |
244 | if (plugin->fin_func) { |
245 | return plugin->fin_func(ctx); |
246 | } |
247 | |
248 | return GRN_SUCCESS; |
249 | } |
250 | |
251 | static grn_rc |
252 | grn_plugin_initialize(grn_ctx *ctx, grn_plugin *plugin, |
253 | grn_dl dl, grn_id id, const char *path) |
254 | { |
255 | plugin->dl = dl; |
256 | |
257 | #define GET_SYMBOL(type) do { \ |
258 | grn_dl_clear_error(); \ |
259 | plugin->type ## _func = grn_dl_sym(dl, GRN_PLUGIN_FUNC_PREFIX #type); \ |
260 | if (!plugin->type ## _func) { \ |
261 | const char *label; \ |
262 | label = grn_dl_sym_error_label(); \ |
263 | SERR("%s", label); \ |
264 | } \ |
265 | } while (0) |
266 | |
267 | GET_SYMBOL(init); |
268 | GET_SYMBOL(register); |
269 | GET_SYMBOL(fin); |
270 | |
271 | #undef GET_SYMBOL |
272 | |
273 | if (!plugin->init_func || !plugin->register_func || !plugin->fin_func) { |
274 | ERR(GRN_INVALID_FORMAT, |
275 | "init func (%s) %sfound, " |
276 | "register func (%s) %sfound and " |
277 | "fin func (%s) %sfound" , |
278 | GRN_PLUGIN_FUNC_PREFIX "init" , plugin->init_func ? "" : "not " , |
279 | GRN_PLUGIN_FUNC_PREFIX "register" , plugin->register_func ? "" : "not " , |
280 | GRN_PLUGIN_FUNC_PREFIX "fin" , plugin->fin_func ? "" : "not " ); |
281 | } |
282 | |
283 | if (!ctx->rc) { |
284 | ctx->impl->plugin_path = path; |
285 | grn_plugin_call_init(ctx, id); |
286 | ctx->impl->plugin_path = NULL; |
287 | } |
288 | |
289 | return ctx->rc; |
290 | } |
291 | |
292 | #ifdef GRN_WITH_MRUBY |
293 | static grn_id |
294 | grn_plugin_open_mrb(grn_ctx *ctx, const char *filename, size_t filename_size) |
295 | { |
296 | grn_ctx *plugins_ctx = &grn_plugins_ctx; |
297 | grn_id id = GRN_ID_NIL; |
298 | grn_plugin **plugin = NULL; |
299 | |
300 | grn_ctx_impl_mrb_ensure_init(ctx); |
301 | if (ctx->rc != GRN_SUCCESS) { |
302 | return GRN_ID_NIL; |
303 | } |
304 | |
305 | if (!ctx->impl->mrb.state) { |
306 | ERR(GRN_FUNCTION_NOT_IMPLEMENTED, "mruby support isn't enabled" ); |
307 | return GRN_ID_NIL; |
308 | } |
309 | |
310 | id = grn_hash_add(plugins_ctx, grn_plugins, filename, filename_size, |
311 | (void **)&plugin, NULL); |
312 | if (!id) { |
313 | return id; |
314 | } |
315 | |
316 | { |
317 | grn_ctx *ctx = plugins_ctx; |
318 | *plugin = GRN_MALLOCN(grn_plugin, 1); |
319 | } |
320 | if (!*plugin) { |
321 | grn_hash_delete_by_id(plugins_ctx, grn_plugins, id, NULL); |
322 | return GRN_ID_NIL; |
323 | } |
324 | |
325 | grn_memcpy((*plugin)->path, filename, filename_size); |
326 | (*plugin)->dl = NULL; |
327 | (*plugin)->init_func = NULL; |
328 | (*plugin)->register_func = NULL; |
329 | (*plugin)->fin_func = NULL; |
330 | (*plugin)->refcount = 1; |
331 | |
332 | return id; |
333 | } |
334 | #endif /* GRN_WITH_MRUBY */ |
335 | |
336 | grn_id |
337 | grn_plugin_open(grn_ctx *ctx, const char *filename) |
338 | { |
339 | grn_ctx *plugins_ctx = &grn_plugins_ctx; |
340 | grn_id id = GRN_ID_NIL; |
341 | grn_dl dl; |
342 | grn_plugin **plugin = NULL; |
343 | size_t filename_size; |
344 | |
345 | filename_size = GRN_PLUGIN_KEY_SIZE(filename); |
346 | |
347 | CRITICAL_SECTION_ENTER(grn_plugins_lock); |
348 | if ((id = grn_hash_get(plugins_ctx, grn_plugins, filename, filename_size, |
349 | (void **)&plugin))) { |
350 | (*plugin)->refcount++; |
351 | goto exit; |
352 | } |
353 | |
354 | #ifdef GRN_WITH_MRUBY |
355 | { |
356 | const char *mrb_suffix; |
357 | mrb_suffix = grn_plugin_get_ruby_suffix(); |
358 | if (filename_size > strlen(mrb_suffix) && |
359 | strcmp(filename + (strlen(filename) - strlen(mrb_suffix)), |
360 | mrb_suffix) == 0) { |
361 | id = grn_plugin_open_mrb(ctx, filename, filename_size); |
362 | goto exit; |
363 | } |
364 | } |
365 | #endif /* GRN_WITH_MRUBY */ |
366 | |
367 | if ((dl = grn_dl_open(filename))) { |
368 | if ((id = grn_hash_add(plugins_ctx, grn_plugins, filename, filename_size, |
369 | (void **)&plugin, NULL))) { |
370 | { |
371 | grn_ctx *ctx = plugins_ctx; |
372 | *plugin = GRN_MALLOCN(grn_plugin, 1); |
373 | } |
374 | if (*plugin) { |
375 | grn_memcpy((*plugin)->path, filename, filename_size); |
376 | if (grn_plugin_initialize(ctx, *plugin, dl, id, filename)) { |
377 | { |
378 | grn_ctx *ctx = plugins_ctx; |
379 | GRN_FREE(*plugin); |
380 | } |
381 | *plugin = NULL; |
382 | } |
383 | } |
384 | if (!*plugin) { |
385 | grn_hash_delete_by_id(plugins_ctx, grn_plugins, id, NULL); |
386 | if (grn_dl_close(dl)) { |
387 | /* Now, __FILE__ set in plugin is invalid. */ |
388 | ctx->errline = 0; |
389 | ctx->errfile = NULL; |
390 | } else { |
391 | const char *label; |
392 | label = grn_dl_close_error_label(); |
393 | SERR("%s" , label); |
394 | } |
395 | id = GRN_ID_NIL; |
396 | } else { |
397 | (*plugin)->refcount = 1; |
398 | } |
399 | } else { |
400 | if (!grn_dl_close(dl)) { |
401 | const char *label; |
402 | label = grn_dl_close_error_label(); |
403 | SERR("%s" , label); |
404 | } |
405 | } |
406 | } else { |
407 | const char *label; |
408 | label = grn_dl_open_error_label(); |
409 | SERR("%s" , label); |
410 | } |
411 | |
412 | exit: |
413 | CRITICAL_SECTION_LEAVE(grn_plugins_lock); |
414 | |
415 | return id; |
416 | } |
417 | |
418 | grn_rc |
419 | grn_plugin_close(grn_ctx *ctx, grn_id id) |
420 | { |
421 | grn_ctx *plugins_ctx = &grn_plugins_ctx; |
422 | grn_rc rc; |
423 | grn_plugin *plugin; |
424 | |
425 | if (id == GRN_ID_NIL) { |
426 | return GRN_INVALID_ARGUMENT; |
427 | } |
428 | |
429 | CRITICAL_SECTION_ENTER(grn_plugins_lock); |
430 | if (!grn_hash_get_value(plugins_ctx, grn_plugins, id, &plugin)) { |
431 | rc = GRN_INVALID_ARGUMENT; |
432 | goto exit; |
433 | } |
434 | if (--plugin->refcount) { |
435 | rc = GRN_SUCCESS; |
436 | goto exit; |
437 | } |
438 | if (plugin->dl) { |
439 | grn_plugin_call_fin(ctx, id); |
440 | if (!grn_dl_close(plugin->dl)) { |
441 | const char *label; |
442 | label = grn_dl_close_error_label(); |
443 | SERR("%s" , label); |
444 | } |
445 | } |
446 | { |
447 | grn_ctx *ctx = plugins_ctx; |
448 | GRN_FREE(plugin); |
449 | } |
450 | rc = grn_hash_delete_by_id(plugins_ctx, grn_plugins, id, NULL); |
451 | |
452 | exit: |
453 | CRITICAL_SECTION_LEAVE(grn_plugins_lock); |
454 | |
455 | return rc; |
456 | } |
457 | |
458 | void * |
459 | grn_plugin_sym(grn_ctx *ctx, grn_id id, const char *symbol) |
460 | { |
461 | grn_plugin *plugin; |
462 | grn_dl_symbol func; |
463 | |
464 | if (id == GRN_ID_NIL) { |
465 | return NULL; |
466 | } |
467 | |
468 | CRITICAL_SECTION_ENTER(grn_plugins_lock); |
469 | if (!grn_hash_get_value(&grn_plugins_ctx, grn_plugins, id, &plugin)) { |
470 | func = NULL; |
471 | goto exit; |
472 | } |
473 | grn_dl_clear_error(); |
474 | if (!(func = grn_dl_sym(plugin->dl, symbol))) { |
475 | const char *label; |
476 | label = grn_dl_sym_error_label(); |
477 | SERR("%s" , label); |
478 | } |
479 | |
480 | exit: |
481 | CRITICAL_SECTION_LEAVE(grn_plugins_lock); |
482 | |
483 | return func; |
484 | } |
485 | |
486 | grn_rc |
487 | grn_plugins_init(void) |
488 | { |
489 | CRITICAL_SECTION_INIT(grn_plugins_lock); |
490 | grn_ctx_init(&grn_plugins_ctx, 0); |
491 | grn_plugins = grn_hash_create(&grn_plugins_ctx, NULL, |
492 | PATH_MAX, sizeof(grn_plugin *), |
493 | GRN_OBJ_KEY_VAR_SIZE); |
494 | if (!grn_plugins) { |
495 | grn_ctx_fin(&grn_plugins_ctx); |
496 | return GRN_NO_MEMORY_AVAILABLE; |
497 | } |
498 | return GRN_SUCCESS; |
499 | } |
500 | |
501 | grn_rc |
502 | grn_plugins_fin(void) |
503 | { |
504 | grn_rc rc; |
505 | if (!grn_plugins) { return GRN_INVALID_ARGUMENT; } |
506 | GRN_HASH_EACH(&grn_plugins_ctx, grn_plugins, id, NULL, NULL, NULL, { |
507 | grn_plugin_close(&grn_plugins_ctx, id); |
508 | }); |
509 | rc = grn_hash_close(&grn_plugins_ctx, grn_plugins); |
510 | grn_ctx_fin(&grn_plugins_ctx); |
511 | CRITICAL_SECTION_FIN(grn_plugins_lock); |
512 | return rc; |
513 | } |
514 | |
515 | const char * |
516 | grn_plugin_get_suffix(void) |
517 | { |
518 | return GRN_PLUGIN_SUFFIX; |
519 | } |
520 | |
521 | const char * |
522 | grn_plugin_get_ruby_suffix(void) |
523 | { |
524 | return ".rb" ; |
525 | } |
526 | |
527 | grn_rc |
528 | grn_plugin_register_by_path(grn_ctx *ctx, const char *path) |
529 | { |
530 | grn_obj *db; |
531 | if (!ctx || !ctx->impl || !(db = ctx->impl->db)) { |
532 | ERR(GRN_INVALID_ARGUMENT, "db not initialized" ); |
533 | return ctx->rc; |
534 | } |
535 | GRN_API_ENTER; |
536 | if (GRN_DB_P(db)) { |
537 | grn_id id; |
538 | id = grn_plugin_open(ctx, path); |
539 | if (id) { |
540 | ctx->impl->plugin_path = path; |
541 | ctx->rc = grn_plugin_call_register(ctx, id); |
542 | ctx->impl->plugin_path = NULL; |
543 | grn_plugin_close(ctx, id); |
544 | } |
545 | } else { |
546 | ERR(GRN_INVALID_ARGUMENT, "invalid db assigned" ); |
547 | } |
548 | GRN_API_RETURN(ctx->rc); |
549 | } |
550 | |
551 | #ifdef WIN32 |
552 | static char *windows_plugins_dir = NULL; |
553 | static char windows_plugins_dir_buffer[PATH_MAX]; |
554 | static const char * |
555 | grn_plugin_get_default_system_plugins_dir(void) |
556 | { |
557 | if (!windows_plugins_dir) { |
558 | const char *base_dir; |
559 | const char *relative_path = GRN_RELATIVE_PLUGINS_DIR; |
560 | size_t base_dir_length; |
561 | |
562 | base_dir = grn_windows_base_dir(); |
563 | base_dir_length = strlen(base_dir); |
564 | grn_strcpy(windows_plugins_dir_buffer, PATH_MAX, base_dir); |
565 | grn_strcat(windows_plugins_dir_buffer, PATH_MAX, "/" ); |
566 | grn_strcat(windows_plugins_dir_buffer, PATH_MAX, relative_path); |
567 | windows_plugins_dir = windows_plugins_dir_buffer; |
568 | } |
569 | return windows_plugins_dir; |
570 | } |
571 | |
572 | #else /* WIN32 */ |
573 | static const char * |
574 | grn_plugin_get_default_system_plugins_dir(void) |
575 | { |
576 | return GRN_PLUGINS_DIR; |
577 | } |
578 | #endif /* WIN32 */ |
579 | |
580 | const char * |
581 | grn_plugin_get_system_plugins_dir(void) |
582 | { |
583 | if (grn_plugins_dir[0]) { |
584 | return grn_plugins_dir; |
585 | } else { |
586 | return grn_plugin_get_default_system_plugins_dir(); |
587 | } |
588 | } |
589 | |
590 | static char * |
591 | grn_plugin_find_path_raw(grn_ctx *ctx, const char *path) |
592 | { |
593 | struct stat path_stat; |
594 | |
595 | if (stat(path, &path_stat) != 0) { |
596 | return NULL; |
597 | } |
598 | |
599 | if (!S_ISREG(path_stat.st_mode)) { |
600 | return NULL; |
601 | } |
602 | |
603 | return GRN_STRDUP(path); |
604 | } |
605 | |
606 | #ifdef GRN_WITH_MRUBY |
607 | static char * |
608 | grn_plugin_find_path_mrb(grn_ctx *ctx, const char *path, size_t path_len) |
609 | { |
610 | char mrb_path[PATH_MAX]; |
611 | const char *mrb_suffix; |
612 | size_t mrb_path_len; |
613 | |
614 | grn_ctx_impl_mrb_ensure_init(ctx); |
615 | if (ctx->rc != GRN_SUCCESS) { |
616 | return NULL; |
617 | } |
618 | |
619 | if (!ctx->impl->mrb.state) { |
620 | return NULL; |
621 | } |
622 | |
623 | mrb_suffix = grn_plugin_get_ruby_suffix(); |
624 | mrb_path_len = path_len + strlen(mrb_suffix); |
625 | if (mrb_path_len >= PATH_MAX) { |
626 | ERR(GRN_FILENAME_TOO_LONG, |
627 | "too long plugin path: <%s%s>" , |
628 | path, mrb_suffix); |
629 | return NULL; |
630 | } |
631 | |
632 | grn_strcpy(mrb_path, PATH_MAX, path); |
633 | grn_strcat(mrb_path, PATH_MAX, mrb_suffix); |
634 | return grn_plugin_find_path_raw(ctx, mrb_path); |
635 | } |
636 | #else /* GRN_WITH_MRUBY */ |
637 | static char * |
638 | grn_plugin_find_path_mrb(grn_ctx *ctx, const char *path, size_t path_len) |
639 | { |
640 | return NULL; |
641 | } |
642 | #endif /* GRN_WITH_MRUBY */ |
643 | |
644 | static char * |
645 | grn_plugin_find_path_so(grn_ctx *ctx, const char *path, size_t path_len) |
646 | { |
647 | char so_path[PATH_MAX]; |
648 | const char *so_suffix; |
649 | size_t so_path_len; |
650 | |
651 | so_suffix = grn_plugin_get_suffix(); |
652 | so_path_len = path_len + strlen(so_suffix); |
653 | if (so_path_len >= PATH_MAX) { |
654 | ERR(GRN_FILENAME_TOO_LONG, |
655 | "too long plugin path: <%s%s>" , |
656 | path, so_suffix); |
657 | return NULL; |
658 | } |
659 | |
660 | grn_strcpy(so_path, PATH_MAX, path); |
661 | grn_strcat(so_path, PATH_MAX, so_suffix); |
662 | return grn_plugin_find_path_raw(ctx, so_path); |
663 | } |
664 | |
665 | static char * |
666 | grn_plugin_find_path_libs_so(grn_ctx *ctx, const char *path, size_t path_len) |
667 | { |
668 | char libs_so_path[PATH_MAX]; |
669 | const char *base_name; |
670 | const char *so_suffix; |
671 | const char *libs_path = "/.libs" ; |
672 | size_t libs_so_path_len; |
673 | |
674 | base_name = strrchr(path, '/'); |
675 | if (!base_name) { |
676 | return NULL; |
677 | } |
678 | |
679 | so_suffix = grn_plugin_get_suffix(); |
680 | libs_so_path_len = |
681 | base_name - path + |
682 | strlen(libs_path) + |
683 | strlen(base_name) + |
684 | strlen(so_suffix); |
685 | if (libs_so_path_len >= PATH_MAX) { |
686 | ERR(GRN_FILENAME_TOO_LONG, |
687 | "too long plugin path: <%.*s/.libs%s%s>" , |
688 | (int)(base_name - path), path, base_name, so_suffix); |
689 | return NULL; |
690 | } |
691 | |
692 | libs_so_path[0] = '\0'; |
693 | grn_strncat(libs_so_path, PATH_MAX, path, base_name - path); |
694 | grn_strcat(libs_so_path, PATH_MAX, libs_path); |
695 | grn_strcat(libs_so_path, PATH_MAX, base_name); |
696 | grn_strcat(libs_so_path, PATH_MAX, so_suffix); |
697 | return grn_plugin_find_path_raw(ctx, libs_so_path); |
698 | } |
699 | |
700 | char * |
701 | grn_plugin_find_path(grn_ctx *ctx, const char *name) |
702 | { |
703 | const char *plugins_dir; |
704 | char dir_last_char; |
705 | char path[PATH_MAX]; |
706 | int name_length, max_name_length; |
707 | char *found_path = NULL; |
708 | size_t path_len; |
709 | |
710 | GRN_API_ENTER; |
711 | if (name[0] == '/') { |
712 | path[0] = '\0'; |
713 | } else { |
714 | plugins_dir = grn_plugin_get_system_plugins_dir(); |
715 | grn_strcpy(path, PATH_MAX, plugins_dir); |
716 | |
717 | dir_last_char = plugins_dir[strlen(path) - 1]; |
718 | if (dir_last_char != '/') { |
719 | grn_strcat(path, PATH_MAX, "/" ); |
720 | } |
721 | } |
722 | |
723 | name_length = strlen(name); |
724 | max_name_length = PATH_MAX - strlen(path) - 1; |
725 | if (name_length > max_name_length) { |
726 | ERR(GRN_INVALID_ARGUMENT, |
727 | "plugin name is too long: %d (max: %d) <%s%s>" , |
728 | name_length, max_name_length, |
729 | path, name); |
730 | goto exit; |
731 | } |
732 | grn_strcat(path, PATH_MAX, name); |
733 | |
734 | found_path = grn_plugin_find_path_raw(ctx, path); |
735 | if (found_path) { |
736 | goto exit; |
737 | } |
738 | |
739 | path_len = strlen(path); |
740 | |
741 | found_path = grn_plugin_find_path_so(ctx, path, path_len); |
742 | if (found_path) { |
743 | goto exit; |
744 | } |
745 | if (ctx->rc) { |
746 | goto exit; |
747 | } |
748 | |
749 | found_path = grn_plugin_find_path_libs_so(ctx, path, path_len); |
750 | if (found_path) { |
751 | goto exit; |
752 | } |
753 | if (ctx->rc) { |
754 | goto exit; |
755 | } |
756 | |
757 | found_path = grn_plugin_find_path_mrb(ctx, path, path_len); |
758 | if (found_path) { |
759 | goto exit; |
760 | } |
761 | if (ctx->rc) { |
762 | goto exit; |
763 | } |
764 | |
765 | exit : |
766 | GRN_API_RETURN(found_path); |
767 | } |
768 | |
769 | static void |
770 | grn_plugin_set_name_resolve_error(grn_ctx *ctx, const char *name, |
771 | const char *tag) |
772 | { |
773 | const char *prefix, *prefix_separator, *suffix; |
774 | |
775 | if (name[0] == '/') { |
776 | prefix = "" ; |
777 | prefix_separator = "" ; |
778 | suffix = "" ; |
779 | } else { |
780 | prefix = grn_plugin_get_system_plugins_dir(); |
781 | if (prefix[strlen(prefix) - 1] != '/') { |
782 | prefix_separator = "/" ; |
783 | } else { |
784 | prefix_separator = "" ; |
785 | } |
786 | suffix = grn_plugin_get_suffix(); |
787 | } |
788 | ERR(GRN_NO_SUCH_FILE_OR_DIRECTORY, |
789 | "%s cannot find plugin file: <%s%s%s%s>" , |
790 | tag, prefix, prefix_separator, name, suffix); |
791 | } |
792 | |
793 | grn_rc |
794 | grn_plugin_register(grn_ctx *ctx, const char *name) |
795 | { |
796 | grn_rc rc; |
797 | char *path; |
798 | |
799 | GRN_API_ENTER; |
800 | path = grn_plugin_find_path(ctx, name); |
801 | if (path) { |
802 | rc = grn_plugin_register_by_path(ctx, path); |
803 | GRN_FREE(path); |
804 | } else { |
805 | if (ctx->rc == GRN_SUCCESS) { |
806 | grn_plugin_set_name_resolve_error(ctx, name, "[plugin][register]" ); |
807 | } |
808 | rc = ctx->rc; |
809 | } |
810 | GRN_API_RETURN(rc); |
811 | } |
812 | |
813 | grn_rc |
814 | grn_plugin_unregister_by_path(grn_ctx *ctx, const char *path) |
815 | { |
816 | grn_obj *db; |
817 | grn_id plugin_id; |
818 | |
819 | if (!ctx || !ctx->impl) { |
820 | ERR(GRN_INVALID_ARGUMENT, "[plugin][unregister] ctx isn't initialized" ); |
821 | return ctx->rc; |
822 | } |
823 | |
824 | db = ctx->impl->db; |
825 | if (!db) { |
826 | ERR(GRN_INVALID_ARGUMENT, "[plugin][unregister] DB isn't initialized" ); |
827 | return ctx->rc; |
828 | } |
829 | |
830 | GRN_API_ENTER; |
831 | |
832 | CRITICAL_SECTION_ENTER(grn_plugins_lock); |
833 | plugin_id = grn_hash_get(&grn_plugins_ctx, grn_plugins, |
834 | path, GRN_PLUGIN_KEY_SIZE(path), |
835 | NULL); |
836 | CRITICAL_SECTION_LEAVE(grn_plugins_lock); |
837 | |
838 | if (plugin_id == GRN_ID_NIL) { |
839 | GRN_API_RETURN(ctx->rc); |
840 | } |
841 | |
842 | { |
843 | grn_table_cursor *cursor; |
844 | grn_id id; |
845 | |
846 | cursor = grn_table_cursor_open(ctx, db, |
847 | NULL, 0, |
848 | NULL, 0, |
849 | 0, -1, GRN_CURSOR_BY_ID); |
850 | if (!cursor) { |
851 | GRN_API_RETURN(ctx->rc); |
852 | } |
853 | |
854 | while ((id = grn_table_cursor_next(ctx, cursor))) { |
855 | grn_obj *obj; |
856 | obj = grn_ctx_at(ctx, id); |
857 | if (!obj) { |
858 | continue; |
859 | } |
860 | if (obj->header.type == GRN_PROC && DB_OBJ(obj)->range == plugin_id) { |
861 | grn_obj_remove(ctx, obj); |
862 | } else { |
863 | grn_obj_unlink(ctx, obj); |
864 | } |
865 | } |
866 | grn_table_cursor_close(ctx, cursor); |
867 | } |
868 | |
869 | GRN_API_RETURN(ctx->rc); |
870 | } |
871 | |
872 | grn_rc |
873 | grn_plugin_unregister(grn_ctx *ctx, const char *name) |
874 | { |
875 | grn_rc rc; |
876 | char *path; |
877 | |
878 | GRN_API_ENTER; |
879 | path = grn_plugin_find_path(ctx, name); |
880 | if (path) { |
881 | rc = grn_plugin_unregister_by_path(ctx, path); |
882 | GRN_FREE(path); |
883 | } else { |
884 | if (ctx->rc == GRN_SUCCESS) { |
885 | grn_plugin_set_name_resolve_error(ctx, name, "[plugin][unregister]" ); |
886 | } |
887 | rc = ctx->rc; |
888 | } |
889 | GRN_API_RETURN(rc); |
890 | } |
891 | |
892 | void |
893 | grn_plugin_ensure_registered(grn_ctx *ctx, grn_obj *proc) |
894 | { |
895 | #ifdef GRN_WITH_MRUBY |
896 | grn_id plugin_id; |
897 | grn_plugin *plugin = NULL; |
898 | |
899 | if (!(proc->header.flags & GRN_OBJ_CUSTOM_NAME)) { |
900 | return; |
901 | } |
902 | |
903 | plugin_id = DB_OBJ(proc)->range; |
904 | CRITICAL_SECTION_ENTER(grn_plugins_lock); |
905 | { |
906 | const char *value; |
907 | value = grn_hash_get_value_(&grn_plugins_ctx, grn_plugins, plugin_id, NULL); |
908 | if (value) { |
909 | plugin = *((grn_plugin **)value); |
910 | } |
911 | } |
912 | CRITICAL_SECTION_LEAVE(grn_plugins_lock); |
913 | |
914 | if (!plugin) { |
915 | return; |
916 | } |
917 | |
918 | if (plugin->dl) { |
919 | return; |
920 | } |
921 | |
922 | grn_ctx_impl_mrb_ensure_init(ctx); |
923 | if (ctx->rc != GRN_SUCCESS) { |
924 | return; |
925 | } |
926 | |
927 | if (!ctx->impl->mrb.state) { |
928 | return; |
929 | } |
930 | |
931 | { |
932 | grn_id id; |
933 | int added; |
934 | id = DB_OBJ(proc)->id; |
935 | grn_hash_add(ctx, ctx->impl->mrb.checked_procs, |
936 | &id, sizeof(grn_id), NULL, &added); |
937 | if (!added) { |
938 | return; |
939 | } |
940 | } |
941 | |
942 | ctx->impl->plugin_path = plugin->path; |
943 | grn_plugin_call_register_mrb(ctx, plugin_id, plugin); |
944 | ctx->impl->plugin_path = NULL; |
945 | #endif /* GRN_WITH_MRUBY */ |
946 | } |
947 | |
948 | grn_rc |
949 | grn_plugin_get_names(grn_ctx *ctx, grn_obj *names) |
950 | { |
951 | grn_hash *processed_paths; |
952 | const char *system_plugins_dir; |
953 | const char *native_plugin_suffix; |
954 | const char *ruby_plugin_suffix; |
955 | grn_bool is_close_opened_object_mode = GRN_FALSE; |
956 | |
957 | GRN_API_ENTER; |
958 | |
959 | if (ctx->rc) { |
960 | GRN_API_RETURN(ctx->rc); |
961 | } |
962 | |
963 | if (grn_thread_get_limit() == 1) { |
964 | is_close_opened_object_mode = GRN_TRUE; |
965 | } |
966 | |
967 | processed_paths = grn_hash_create(ctx, NULL, GRN_TABLE_MAX_KEY_SIZE, 0, |
968 | GRN_OBJ_TABLE_HASH_KEY | |
969 | GRN_OBJ_KEY_VAR_SIZE); |
970 | if (!processed_paths) { |
971 | GRN_API_RETURN(ctx->rc); |
972 | } |
973 | |
974 | system_plugins_dir = grn_plugin_get_system_plugins_dir(); |
975 | native_plugin_suffix = grn_plugin_get_suffix(); |
976 | ruby_plugin_suffix = grn_plugin_get_ruby_suffix(); |
977 | |
978 | GRN_TABLE_EACH_BEGIN_FLAGS(ctx, grn_ctx_db(ctx), cursor, id, |
979 | GRN_CURSOR_BY_ID | GRN_CURSOR_ASCENDING) { |
980 | void *name; |
981 | int name_size; |
982 | grn_obj *object; |
983 | const char *path; |
984 | grn_id processed_path_id; |
985 | |
986 | if (grn_id_is_builtin(ctx, id)) { |
987 | continue; |
988 | } |
989 | |
990 | name_size = grn_table_cursor_get_key(ctx, cursor, &name); |
991 | if (grn_obj_name_is_column(ctx, name, name_size)) { |
992 | continue; |
993 | } |
994 | |
995 | if (is_close_opened_object_mode) { |
996 | grn_ctx_push_temporary_open_space(ctx); |
997 | } |
998 | |
999 | object = grn_ctx_at(ctx, id); |
1000 | if (!object) { |
1001 | ERRCLR(ctx); |
1002 | goto next_loop; |
1003 | } |
1004 | |
1005 | if (!grn_obj_is_proc(ctx, object)) { |
1006 | goto next_loop; |
1007 | } |
1008 | |
1009 | path = grn_obj_path(ctx, object); |
1010 | if (!path) { |
1011 | goto next_loop; |
1012 | } |
1013 | |
1014 | processed_path_id = grn_hash_get(ctx, processed_paths, |
1015 | path, strlen(path), |
1016 | NULL); |
1017 | if (processed_path_id != GRN_ID_NIL) { |
1018 | goto next_loop; |
1019 | } |
1020 | |
1021 | grn_hash_add(ctx, processed_paths, |
1022 | path, strlen(path), |
1023 | NULL, NULL); |
1024 | |
1025 | { |
1026 | const char *relative_path; |
1027 | const char *libs_path = "/.libs/" ; |
1028 | const char *start_libs; |
1029 | char name[PATH_MAX]; |
1030 | |
1031 | name[0] = '\0'; |
1032 | if (strncmp(path, system_plugins_dir, strlen(system_plugins_dir)) == 0) { |
1033 | relative_path = path + strlen(system_plugins_dir); |
1034 | } else { |
1035 | relative_path = path; |
1036 | } |
1037 | start_libs = strstr(relative_path, libs_path); |
1038 | if (start_libs) { |
1039 | grn_strncat(name, PATH_MAX, relative_path, start_libs - relative_path); |
1040 | grn_strcat(name, PATH_MAX, "/" ); |
1041 | grn_strcat(name, PATH_MAX, start_libs + strlen(libs_path)); |
1042 | } else { |
1043 | grn_strcat(name, PATH_MAX, relative_path); |
1044 | } |
1045 | if (strlen(name) > strlen(native_plugin_suffix) && |
1046 | strcmp(name + strlen(name) - strlen(native_plugin_suffix), |
1047 | native_plugin_suffix) == 0) { |
1048 | name[strlen(name) - strlen(native_plugin_suffix)] = '\0'; |
1049 | } else if (strlen(name) > strlen(ruby_plugin_suffix) && |
1050 | strcmp(name + strlen(name) - strlen(ruby_plugin_suffix), |
1051 | ruby_plugin_suffix) == 0) { |
1052 | name[strlen(name) - strlen(ruby_plugin_suffix)] = '\0'; |
1053 | } |
1054 | grn_vector_add_element(ctx, names, |
1055 | name, strlen(name), |
1056 | 0, GRN_DB_TEXT); |
1057 | } |
1058 | |
1059 | next_loop : |
1060 | if (is_close_opened_object_mode) { |
1061 | grn_ctx_pop_temporary_open_space(ctx); |
1062 | } |
1063 | } GRN_TABLE_EACH_END(ctx, cursor); |
1064 | |
1065 | grn_hash_close(ctx, processed_paths); |
1066 | |
1067 | GRN_API_RETURN(ctx->rc); |
1068 | } |
1069 | |
1070 | void * |
1071 | grn_plugin_malloc(grn_ctx *ctx, size_t size, const char *file, int line, |
1072 | const char *func) |
1073 | { |
1074 | return grn_malloc(ctx, size, file, line, func); |
1075 | } |
1076 | |
1077 | void * |
1078 | grn_plugin_calloc(grn_ctx *ctx, size_t size, const char *file, int line, |
1079 | const char *func) |
1080 | { |
1081 | return grn_calloc(ctx, size, file, line, func); |
1082 | } |
1083 | |
1084 | void * |
1085 | grn_plugin_realloc(grn_ctx *ctx, void *ptr, size_t size, |
1086 | const char *file, int line, const char *func) |
1087 | { |
1088 | return grn_realloc(ctx, ptr, size, file, line, func); |
1089 | } |
1090 | |
1091 | void |
1092 | grn_plugin_free(grn_ctx *ctx, void *ptr, const char *file, int line, |
1093 | const char *func) |
1094 | { |
1095 | grn_free(ctx, ptr, file, line, func); |
1096 | } |
1097 | |
1098 | void |
1099 | grn_plugin_set_error(grn_ctx *ctx, grn_log_level level, grn_rc error_code, |
1100 | const char *file, int line, const char *func, |
1101 | const char *format, ...) |
1102 | { |
1103 | char old_error_message[GRN_CTX_MSGSIZE]; |
1104 | |
1105 | ctx->errlvl = level; |
1106 | ctx->rc = error_code; |
1107 | ctx->errfile = file; |
1108 | ctx->errline = line; |
1109 | ctx->errfunc = func; |
1110 | |
1111 | grn_strcpy(old_error_message, GRN_CTX_MSGSIZE, ctx->errbuf); |
1112 | |
1113 | { |
1114 | va_list ap; |
1115 | va_start(ap, format); |
1116 | grn_ctx_logv(ctx, format, ap); |
1117 | va_end(ap); |
1118 | } |
1119 | |
1120 | if (grn_ctx_impl_should_log(ctx)) { |
1121 | grn_ctx_impl_set_current_error_message(ctx); |
1122 | if (grn_logger_pass(ctx, level)) { |
1123 | char new_error_message[GRN_CTX_MSGSIZE]; |
1124 | grn_strcpy(new_error_message, GRN_CTX_MSGSIZE, ctx->errbuf); |
1125 | grn_strcpy(ctx->errbuf, GRN_CTX_MSGSIZE, old_error_message); |
1126 | { |
1127 | va_list ap; |
1128 | va_start(ap, format); |
1129 | grn_logger_putv(ctx, level, file, line, func, format, ap); |
1130 | va_end(ap); |
1131 | } |
1132 | grn_strcpy(ctx->errbuf, GRN_CTX_MSGSIZE, new_error_message); |
1133 | } |
1134 | if (level <= GRN_LOG_ERROR) { |
1135 | grn_plugin_logtrace(ctx, level); |
1136 | } |
1137 | } |
1138 | } |
1139 | |
1140 | void |
1141 | grn_plugin_clear_error(grn_ctx *ctx) |
1142 | { |
1143 | ERRCLR(ctx); |
1144 | } |
1145 | |
1146 | void |
1147 | grn_plugin_backtrace(grn_ctx *ctx) |
1148 | { |
1149 | BACKTRACE(ctx); |
1150 | } |
1151 | |
1152 | void |
1153 | grn_plugin_logtrace(grn_ctx *ctx, grn_log_level level) |
1154 | { |
1155 | if (level <= GRN_LOG_ERROR) { |
1156 | grn_plugin_backtrace(ctx); |
1157 | LOGTRACE(ctx, level); |
1158 | } |
1159 | } |
1160 | |
1161 | struct _grn_plugin_mutex { |
1162 | grn_critical_section critical_section; |
1163 | }; |
1164 | |
1165 | grn_plugin_mutex * |
1166 | grn_plugin_mutex_open(grn_ctx *ctx) |
1167 | { |
1168 | grn_plugin_mutex * const mutex = |
1169 | GRN_PLUGIN_MALLOC(ctx, sizeof(grn_plugin_mutex)); |
1170 | if (mutex != NULL) { |
1171 | CRITICAL_SECTION_INIT(mutex->critical_section); |
1172 | } |
1173 | return mutex; |
1174 | } |
1175 | |
1176 | grn_plugin_mutex * |
1177 | grn_plugin_mutex_create(grn_ctx *ctx) |
1178 | { |
1179 | return grn_plugin_mutex_open(ctx); |
1180 | } |
1181 | |
1182 | void |
1183 | grn_plugin_mutex_close(grn_ctx *ctx, grn_plugin_mutex *mutex) |
1184 | { |
1185 | if (mutex != NULL) { |
1186 | CRITICAL_SECTION_FIN(mutex->critical_section); |
1187 | GRN_PLUGIN_FREE(ctx, mutex); |
1188 | } |
1189 | } |
1190 | |
1191 | void |
1192 | grn_plugin_mutex_destroy(grn_ctx *ctx, grn_plugin_mutex *mutex) |
1193 | { |
1194 | grn_plugin_mutex_close(ctx, mutex); |
1195 | } |
1196 | |
1197 | void |
1198 | grn_plugin_mutex_lock(grn_ctx *ctx, grn_plugin_mutex *mutex) |
1199 | { |
1200 | if (mutex != NULL) { |
1201 | CRITICAL_SECTION_ENTER(mutex->critical_section); |
1202 | } |
1203 | } |
1204 | |
1205 | void |
1206 | grn_plugin_mutex_unlock(grn_ctx *ctx, grn_plugin_mutex *mutex) |
1207 | { |
1208 | if (mutex != NULL) { |
1209 | CRITICAL_SECTION_LEAVE(mutex->critical_section); |
1210 | } |
1211 | } |
1212 | |
1213 | grn_obj * |
1214 | grn_plugin_proc_alloc(grn_ctx *ctx, grn_user_data *user_data, |
1215 | grn_id domain, unsigned char flags) |
1216 | { |
1217 | return grn_proc_alloc(ctx, user_data, domain, flags); |
1218 | } |
1219 | |
1220 | grn_obj * |
1221 | grn_plugin_proc_get_vars(grn_ctx *ctx, grn_user_data *user_data) |
1222 | { |
1223 | return grn_proc_get_vars(ctx, user_data); |
1224 | } |
1225 | |
1226 | grn_obj * |
1227 | grn_plugin_proc_get_var(grn_ctx *ctx, grn_user_data *user_data, |
1228 | const char *name, int name_size) |
1229 | { |
1230 | name_size = compute_name_size(name, name_size); |
1231 | return grn_proc_get_var(ctx, user_data, name, name_size); |
1232 | } |
1233 | |
1234 | grn_bool |
1235 | grn_plugin_proc_get_var_bool(grn_ctx *ctx, |
1236 | grn_user_data *user_data, |
1237 | const char *name, |
1238 | int name_size, |
1239 | grn_bool default_value) |
1240 | { |
1241 | grn_obj *var; |
1242 | |
1243 | var = grn_plugin_proc_get_var(ctx, user_data, name, name_size); |
1244 | return grn_proc_option_value_bool(ctx, var, default_value); |
1245 | } |
1246 | |
1247 | int32_t |
1248 | grn_plugin_proc_get_var_int32(grn_ctx *ctx, |
1249 | grn_user_data *user_data, |
1250 | const char *name, |
1251 | int name_size, |
1252 | int32_t default_value) |
1253 | { |
1254 | grn_obj *var; |
1255 | |
1256 | var = grn_plugin_proc_get_var(ctx, user_data, name, name_size); |
1257 | return grn_proc_option_value_int32(ctx, var, default_value); |
1258 | } |
1259 | |
1260 | const char * |
1261 | grn_plugin_proc_get_var_string(grn_ctx *ctx, |
1262 | grn_user_data *user_data, |
1263 | const char *name, |
1264 | int name_size, |
1265 | size_t *size) |
1266 | { |
1267 | grn_obj *var; |
1268 | |
1269 | var = grn_plugin_proc_get_var(ctx, user_data, name, name_size); |
1270 | return grn_proc_option_value_string(ctx, var, size); |
1271 | } |
1272 | |
1273 | grn_content_type |
1274 | grn_plugin_proc_get_var_content_type(grn_ctx *ctx, |
1275 | grn_user_data *user_data, |
1276 | const char *name, |
1277 | int name_size, |
1278 | grn_content_type default_value) |
1279 | { |
1280 | grn_obj *var; |
1281 | |
1282 | var = grn_plugin_proc_get_var(ctx, user_data, name, name_size); |
1283 | return grn_proc_option_value_content_type(ctx, var, default_value); |
1284 | } |
1285 | |
1286 | grn_obj * |
1287 | grn_plugin_proc_get_var_by_offset(grn_ctx *ctx, grn_user_data *user_data, |
1288 | unsigned int offset) |
1289 | { |
1290 | return grn_proc_get_var_by_offset(ctx, user_data, offset); |
1291 | } |
1292 | |
1293 | grn_obj * |
1294 | grn_plugin_proc_get_caller(grn_ctx *ctx, grn_user_data *user_data) |
1295 | { |
1296 | grn_obj *caller = NULL; |
1297 | GRN_API_ENTER; |
1298 | grn_proc_get_info(ctx, user_data, NULL, NULL, &caller); |
1299 | GRN_API_RETURN(caller); |
1300 | } |
1301 | |
1302 | const char * |
1303 | grn_plugin_win32_base_dir(void) |
1304 | { |
1305 | return grn_plugin_windows_base_dir(); |
1306 | } |
1307 | |
1308 | const char * |
1309 | grn_plugin_windows_base_dir(void) |
1310 | { |
1311 | #ifdef WIN32 |
1312 | return grn_windows_base_dir(); |
1313 | #else /* WIN32 */ |
1314 | return NULL; |
1315 | #endif /* WIN32 */ |
1316 | } |
1317 | |
1318 | /* |
1319 | grn_plugin_charlen() takes the length of a string, unlike grn_charlen_(). |
1320 | */ |
1321 | int |
1322 | grn_plugin_charlen(grn_ctx *ctx, const char *str_ptr, |
1323 | unsigned int str_length, grn_encoding encoding) |
1324 | { |
1325 | return grn_charlen_(ctx, str_ptr, str_ptr + str_length, encoding); |
1326 | } |
1327 | |
1328 | /* |
1329 | grn_plugin_isspace() takes the length of a string, unlike grn_isspace(). |
1330 | */ |
1331 | int |
1332 | grn_plugin_isspace(grn_ctx *ctx, const char *str_ptr, |
1333 | unsigned int str_length, grn_encoding encoding) |
1334 | { |
1335 | if ((str_ptr == NULL) || (str_length == 0)) { |
1336 | return 0; |
1337 | } |
1338 | switch ((unsigned char)str_ptr[0]) { |
1339 | case ' ' : |
1340 | case '\f' : |
1341 | case '\n' : |
1342 | case '\r' : |
1343 | case '\t' : |
1344 | case '\v' : |
1345 | return 1; |
1346 | case 0x81 : |
1347 | if ((encoding == GRN_ENC_SJIS) && (str_length >= 2) && |
1348 | ((unsigned char)str_ptr[1] == 0x40)) { |
1349 | return 2; |
1350 | } |
1351 | break; |
1352 | case 0xA1 : |
1353 | if ((encoding == GRN_ENC_EUC_JP) && (str_length >= 2) && |
1354 | ((unsigned char)str_ptr[1] == 0xA1)) { |
1355 | return 2; |
1356 | } |
1357 | break; |
1358 | case 0xE3 : |
1359 | if ((encoding == GRN_ENC_UTF8) && (str_length >= 3) && |
1360 | ((unsigned char)str_ptr[1] == 0x80) && |
1361 | ((unsigned char)str_ptr[2] == 0x80)) { |
1362 | return 3; |
1363 | } |
1364 | break; |
1365 | default : |
1366 | break; |
1367 | } |
1368 | return 0; |
1369 | } |
1370 | |
1371 | grn_rc |
1372 | grn_plugin_expr_var_init(grn_ctx *ctx, |
1373 | grn_expr_var *var, |
1374 | const char *name, |
1375 | int name_size) |
1376 | { |
1377 | var->name = name; |
1378 | var->name_size = compute_name_size(name, name_size); |
1379 | GRN_TEXT_INIT(&var->value, 0); |
1380 | return GRN_SUCCESS; |
1381 | } |
1382 | |
1383 | grn_obj * |
1384 | grn_plugin_command_create(grn_ctx *ctx, |
1385 | const char *name, |
1386 | int name_size, |
1387 | grn_proc_func func, |
1388 | unsigned int n_vars, |
1389 | grn_expr_var *vars) |
1390 | { |
1391 | grn_obj *proc; |
1392 | name_size = compute_name_size(name, name_size); |
1393 | proc = grn_proc_create(ctx, name, name_size, GRN_PROC_COMMAND, |
1394 | func, NULL, NULL, n_vars, vars); |
1395 | return proc; |
1396 | } |
1397 | |