1/* -*- c-basic-offset: 2 -*- */
2/*
3 Copyright(C) 2015 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
19#include "../grn_ctx_impl.h"
20#include <groonga/command.h>
21
22#ifdef GRN_WITH_MRUBY
23#include <mruby.h>
24#include <mruby/class.h>
25#include <mruby/data.h>
26#include <mruby/value.h>
27#include <mruby/string.h>
28
29#include "mrb_ctx.h"
30#include "mrb_command.h"
31
32static struct mrb_data_type mrb_grn_command_type = {
33 "Groonga::Command",
34 NULL
35};
36
37mrb_value
38mrb_grn_command_instantiate(grn_ctx *ctx, grn_obj *command)
39{
40 grn_mrb_data *data = &(ctx->impl->mrb);
41 mrb_state *mrb = data->state;
42 struct RClass *module = data->module;
43 char name[GRN_TABLE_MAX_KEY_SIZE];
44 int name_size;
45 mrb_value mrb_name;
46 struct RClass *command_class;
47 struct RClass *target_command_class;
48 mrb_value mrb_target_command_class;
49 mrb_value mrb_arguments[1];
50
51 name_size = grn_obj_name(ctx, command, name, GRN_TABLE_MAX_KEY_SIZE);
52 mrb_name = mrb_str_new(mrb, name, name_size);
53
54 command_class = mrb_class_get_under(mrb, module, "Command");
55 mrb_target_command_class = mrb_funcall(mrb,
56 mrb_obj_value(command_class),
57 "find_class", 1, mrb_name);
58 if (mrb_nil_p(mrb_target_command_class)) {
59 target_command_class = command_class;
60 } else {
61 target_command_class = mrb_class_ptr(mrb_target_command_class);
62 }
63 mrb_arguments[0] = mrb_cptr_value(mrb, command);
64 return mrb_obj_new(mrb, target_command_class, 1, mrb_arguments);
65}
66
67static void
68mrb_grn_command_run_wrapper(grn_ctx *ctx,
69 grn_obj *command,
70 grn_command_input *input,
71 void *user_data)
72{
73 grn_mrb_data *data = &(ctx->impl->mrb);
74 mrb_state *mrb = data->state;
75 struct RClass *module = data->module;
76 int arena_index;
77 mrb_value mrb_command;
78 mrb_value mrb_input;
79
80 arena_index = mrb_gc_arena_save(mrb);
81 mrb_command = mrb_grn_command_instantiate(ctx, command);
82 {
83 struct RClass *command_input_class;
84 mrb_value mrb_arguments[1];
85 command_input_class = mrb_class_get_under(mrb, module, "CommandInput");
86 mrb_arguments[0] = mrb_cptr_value(mrb, input);
87 mrb_input = mrb_obj_new(mrb, command_input_class, 1, mrb_arguments);
88 }
89 mrb_funcall(mrb, mrb_command, "run_internal", 1, mrb_input);
90 if (ctx->rc == GRN_SUCCESS && mrb->exc) {
91 char name[GRN_TABLE_MAX_KEY_SIZE];
92 int name_size;
93 name_size = grn_obj_name(ctx, command, name, GRN_TABLE_MAX_KEY_SIZE);
94 if (mrb->exc == mrb->nomem_err) {
95 MERR("failed to allocate memory in mruby: <%.*s>",
96 name_size, name);
97 } else {
98 mrb_value reason;
99 reason = mrb_funcall(mrb, mrb_obj_value(mrb->exc), "inspect", 0);
100 ERR(GRN_COMMAND_ERROR,
101 "failed to run command: <%*.s>: %.*s",
102 name_size, name,
103 (int)RSTRING_LEN(reason), RSTRING_PTR(reason));
104 }
105 }
106 mrb_gc_arena_restore(mrb, arena_index);
107}
108
109static mrb_value
110mrb_grn_command_class_register(mrb_state *mrb, mrb_value klass)
111{
112 grn_ctx *ctx = (grn_ctx *)mrb->ud;
113 mrb_value mrb_name;
114 mrb_value *mrb_arguments;
115 mrb_int n_arguments;
116
117 mrb_get_args(mrb, "Sa", &mrb_name, &mrb_arguments, &n_arguments);
118
119 {
120 grn_expr_var *vars;
121 mrb_int i;
122
123 for (i = 0; i < n_arguments; i++) {
124 mrb_arguments[i] = mrb_convert_type(mrb, mrb_arguments[i],
125 MRB_TT_STRING, "String", "to_str");
126 }
127 vars = GRN_MALLOCN(grn_expr_var, n_arguments);
128 for (i = 0; i < n_arguments; i++) {
129 mrb_value mrb_argument = mrb_arguments[i];
130 grn_expr_var *var = &vars[i];
131 var->name = RSTRING_PTR(mrb_argument);
132 var->name_size = RSTRING_LEN(mrb_argument);
133 GRN_TEXT_INIT(&(var->value), 0);
134 }
135
136 grn_command_register(ctx,
137 RSTRING_PTR(mrb_name),
138 RSTRING_LEN(mrb_name),
139 mrb_grn_command_run_wrapper,
140 vars,
141 n_arguments,
142 NULL);
143
144 for (i = 0; i < n_arguments; i++) {
145 grn_expr_var *var = &vars[i];
146 GRN_OBJ_FIN(ctx, &(var->value));
147 }
148 GRN_FREE(vars);
149 }
150
151 grn_mrb_ctx_check(mrb);
152
153 {
154 grn_mrb_data *data = &(ctx->impl->mrb);
155 struct RClass *command_class;
156 command_class = mrb_class_get_under(mrb, data->module, "Command");
157 mrb_funcall(mrb,
158 mrb_obj_value(command_class),
159 "register_class", 2, mrb_name, klass);
160 }
161
162 return mrb_nil_value();
163}
164
165static mrb_value
166mrb_grn_command_initialize(mrb_state *mrb, mrb_value self)
167{
168 mrb_value mrb_command_ptr;
169
170 mrb_get_args(mrb, "o", &mrb_command_ptr);
171 DATA_TYPE(self) = &mrb_grn_command_type;
172 DATA_PTR(self) = mrb_cptr(mrb_command_ptr);
173 return self;
174}
175
176void
177grn_mrb_command_init(grn_ctx *ctx)
178{
179 grn_mrb_data *data = &(ctx->impl->mrb);
180 mrb_state *mrb = data->state;
181 struct RClass *module = data->module;
182 struct RClass *procedure_class;
183 struct RClass *klass;
184
185 procedure_class = mrb_class_get_under(mrb, module, "Procedure");
186 klass = mrb_define_class_under(mrb, module, "Command", procedure_class);
187 MRB_SET_INSTANCE_TT(klass, MRB_TT_DATA);
188
189 mrb_define_class_method(mrb, klass, "register",
190 mrb_grn_command_class_register,
191 MRB_ARGS_REQ(2));
192
193 mrb_define_method(mrb, klass, "initialize",
194 mrb_grn_command_initialize, MRB_ARGS_REQ(1));
195}
196#endif
197