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-1335  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>
CHorizontalSwitch(size,listener,tag,frames,heightOfOneImage,frames,background,offset)28 
29 #include "mrb_ctx.h"
30 #include "mrb_command.h"
31 
32 static struct mrb_data_type mrb_grn_command_type = {
33   "Groonga::Command",
34   NULL
35 };
36 
37 mrb_value
38 mrb_grn_command_instantiate(grn_ctx *ctx, grn_obj *command)
39 {
40   grn_mrb_data *data = &(ctx->impl->mrb);
41   mrb_state *mrb = data->state;
getIValue()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 
67 static void
onMouseEntered(VSTGUI::CPoint & where,const VSTGUI::CButtonState & buttons)68 mrb_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 
109 static mrb_value
110 mrb_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 
165 static mrb_value
166 mrb_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 
176 void
177 grn_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