1/* vi:set ts=8 sts=4 sw=4:
2 *
3 * VIM - Vi IMproved	by Bram Moolenaar
4 *
5 * Ruby interface by Shugo Maeda
6 *   with improvements by SegPhault (Ryan Paul)
7 *
8 * Do ":help uganda"  in Vim to read copying and usage conditions.
9 * Do ":help credits" in Vim to see a list of people who contributed.
10 * See README.txt for an overview of the Vim source code.
11 */
12
13#include <stdio.h>
14#include <string.h>
15
16#ifdef _WIN32
17# if !defined(DYNAMIC_RUBY_VER) || (DYNAMIC_RUBY_VER < 18)
18#   define NT
19# endif
20# ifndef DYNAMIC_RUBY
21#  define IMPORT /* For static dll usage __declspec(dllimport) */
22#  define RUBYEXTERN __declspec(dllimport)
23# endif
24#endif
25#ifndef RUBYEXTERN
26# define RUBYEXTERN extern
27#endif
28
29/*
30 * This is tricky.  In ruby.h there is (inline) function rb_class_of()
31 * definition.  This function use these variables.  But we want function to
32 * use dll_* variables.
33 */
34#ifdef DYNAMIC_RUBY
35# define rb_cFalseClass		(*dll_rb_cFalseClass)
36# define rb_cFixnum		(*dll_rb_cFixnum)
37# define rb_cNilClass		(*dll_rb_cNilClass)
38# define rb_cSymbol		(*dll_rb_cSymbol)
39# define rb_cTrueClass		(*dll_rb_cTrueClass)
40# if defined(DYNAMIC_RUBY_VER) && DYNAMIC_RUBY_VER >= 18
41/*
42 * On ver 1.8, all Ruby functions are exported with "__declspec(dllimport)"
43 * in ruby.h.  But it causes trouble for these variables, because it is
44 * defined in this file.  When defined this RUBY_EXPORT it modified to
45 * "extern" and be able to avoid this problem.
46 */
47#  define RUBY_EXPORT
48# endif
49#endif
50
51/* suggested by Ariya Mizutani */
52#if (_MSC_VER == 1200)
53# undef _WIN32_WINNT
54#endif
55
56#if (defined(RUBY_VERSION) && RUBY_VERSION >= 19) \
57    || (defined(DYNAMIC_RUBY_VER) && DYNAMIC_RUBY_VER >= 19)
58# define RUBY19_OR_LATER 1
59#endif
60
61#if defined(DYNAMIC_RUBY_VER) && DYNAMIC_RUBY_VER >= 19
62/* Ruby 1.9 defines a number of static functions which use rb_num2long and
63 * rb_int2big */
64# define rb_num2long rb_num2long_stub
65# define rb_int2big rb_int2big_stub
66#endif
67
68#include <ruby.h>
69#ifdef RUBY19_OR_LATER
70# include <ruby/encoding.h>
71#endif
72
73#undef EXTERN
74#undef _
75
76/* T_DATA defined both by Ruby and Mac header files, hack around it... */
77#if defined(MACOS_X_UNIX) || defined(macintosh)
78# define __OPENTRANSPORT__
79# define __OPENTRANSPORTPROTOCOL__
80# define __OPENTRANSPORTPROVIDERS__
81#endif
82
83/*
84 * Backward compatiblity for Ruby 1.8 and earlier.
85 * Ruby 1.9 does not provide STR2CSTR, instead StringValuePtr is provided.
86 * Ruby 1.9 does not provide RXXX(s)->len and RXXX(s)->ptr, instead
87 * RXXX_LEN(s) and RXXX_PTR(s) are provided.
88 */
89#ifndef StringValuePtr
90# define StringValuePtr(s) STR2CSTR(s)
91#endif
92#ifndef RARRAY_LEN
93# define RARRAY_LEN(s) RARRAY(s)->len
94#endif
95#ifndef RARRAY_PTR
96# define RARRAY_PTR(s) RARRAY(s)->ptr
97#endif
98#ifndef RSTRING_LEN
99# define RSTRING_LEN(s) RSTRING(s)->len
100#endif
101#ifndef RSTRING_PTR
102# define RSTRING_PTR(s) RSTRING(s)->ptr
103#endif
104
105#include "vim.h"
106#include "version.h"
107
108#if defined(PROTO) && !defined(FEAT_RUBY)
109/* Define these to be able to generate the function prototypes. */
110# define VALUE int
111# define RUBY_DATA_FUNC int
112#endif
113
114static int ruby_initialized = 0;
115static VALUE objtbl;
116
117static VALUE mVIM;
118static VALUE cBuffer;
119static VALUE cVimWindow;
120static VALUE eDeletedBufferError;
121static VALUE eDeletedWindowError;
122
123static int ensure_ruby_initialized(void);
124static void error_print(int);
125static void ruby_io_init(void);
126static void ruby_vim_init(void);
127
128#if defined(DYNAMIC_RUBY) || defined(PROTO)
129#ifdef PROTO
130# define HINSTANCE int		/* for generating prototypes */
131#endif
132
133#if defined(__APPLE__)
134# include <dlfcn.h>
135# define FARPROC void*
136# define HINSTANCE void*
137# define LoadLibrary(n) dlopen((n), RTLD_LAZY|RTLD_GLOBAL)
138# define GetProcAddress dlsym
139# define FreeLibrary dlclose
140
141# define rb_num2uint dll_rb_num2uint
142# define rb_num2int dll_rb_num2int
143# define rb_fix2int dll_rb_fix2int
144#endif
145
146/*
147 * Wrapper defines
148 */
149#define rb_assoc_new			dll_rb_assoc_new
150#define rb_cObject			(*dll_rb_cObject)
151#define rb_check_type			dll_rb_check_type
152#define rb_class_path			dll_rb_class_path
153#define rb_data_object_alloc		dll_rb_data_object_alloc
154#define rb_define_class_under		dll_rb_define_class_under
155#define rb_define_const			dll_rb_define_const
156#define rb_define_global_function	dll_rb_define_global_function
157#define rb_define_method		dll_rb_define_method
158#define rb_define_module		dll_rb_define_module
159#define rb_define_module_function	dll_rb_define_module_function
160#define rb_define_singleton_method	dll_rb_define_singleton_method
161#define rb_define_virtual_variable	dll_rb_define_virtual_variable
162#define rb_stdout			(*dll_rb_stdout)
163#define rb_eArgError			(*dll_rb_eArgError)
164#define rb_eIndexError			(*dll_rb_eIndexError)
165#define rb_eRuntimeError		(*dll_rb_eRuntimeError)
166#define rb_eStandardError		(*dll_rb_eStandardError)
167#define rb_eval_string_protect		dll_rb_eval_string_protect
168#define rb_global_variable		dll_rb_global_variable
169#define rb_hash_aset			dll_rb_hash_aset
170#define rb_hash_new			dll_rb_hash_new
171#define rb_inspect			dll_rb_inspect
172#define rb_int2inum			dll_rb_int2inum
173#define rb_lastline_get			dll_rb_lastline_get
174#define rb_lastline_set			dll_rb_lastline_set
175#define rb_load_protect			dll_rb_load_protect
176#define rb_num2long			dll_rb_num2long
177#define rb_num2ulong			dll_rb_num2ulong
178#define rb_obj_alloc			dll_rb_obj_alloc
179#define rb_obj_as_string		dll_rb_obj_as_string
180#define rb_obj_id			dll_rb_obj_id
181#define rb_raise			dll_rb_raise
182#define rb_str2cstr			dll_rb_str2cstr
183#define rb_str_cat			dll_rb_str_cat
184#define rb_str_concat			dll_rb_str_concat
185#define rb_str_new			dll_rb_str_new
186#ifdef rb_str_new2
187/* Ruby may #define rb_str_new2 to use rb_str_new_cstr. */
188# define need_rb_str_new_cstr 1
189# define rb_str_new_cstr		dll_rb_str_new_cstr
190#else
191# define rb_str_new2			dll_rb_str_new2
192#endif
193#if defined(DYNAMIC_RUBY_VER) && DYNAMIC_RUBY_VER >= 18
194# define rb_string_value_ptr		dll_rb_string_value_ptr
195# define rb_float_new			dll_rb_float_new
196# define rb_ary_new			dll_rb_ary_new
197# define rb_ary_push			dll_rb_ary_push
198#endif
199#ifdef RUBY19_OR_LATER
200# define rb_errinfo			dll_rb_errinfo
201#else
202# define ruby_errinfo			(*dll_ruby_errinfo)
203#endif
204#define ruby_init			dll_ruby_init
205#define ruby_init_loadpath		dll_ruby_init_loadpath
206#define NtInitialize			dll_NtInitialize
207#if defined(DYNAMIC_RUBY_VER) && DYNAMIC_RUBY_VER >= 18
208# define rb_w32_snprintf		dll_rb_w32_snprintf
209#endif
210
211#ifdef RUBY19_OR_LATER
212# define ruby_script			dll_ruby_script
213# define rb_enc_find_index		dll_rb_enc_find_index
214# define rb_enc_find			dll_rb_enc_find
215# define rb_enc_str_new			dll_rb_enc_str_new
216# define rb_sprintf			dll_rb_sprintf
217# define ruby_init_stack		dll_ruby_init_stack
218#endif
219
220/*
221 * Pointers for dynamic link
222 */
223static VALUE (*dll_rb_assoc_new) (VALUE, VALUE);
224VALUE *dll_rb_cFalseClass;
225VALUE *dll_rb_cFixnum;
226VALUE *dll_rb_cNilClass;
227static VALUE *dll_rb_cObject;
228VALUE *dll_rb_cSymbol;
229VALUE *dll_rb_cTrueClass;
230static void (*dll_rb_check_type) (VALUE,int);
231static VALUE (*dll_rb_class_path) (VALUE);
232static VALUE (*dll_rb_data_object_alloc) (VALUE, void*, RUBY_DATA_FUNC, RUBY_DATA_FUNC);
233static VALUE (*dll_rb_define_class_under) (VALUE, const char*, VALUE);
234static void (*dll_rb_define_const) (VALUE,const char*,VALUE);
235static void (*dll_rb_define_global_function) (const char*,VALUE(*)(),int);
236static void (*dll_rb_define_method) (VALUE,const char*,VALUE(*)(),int);
237static VALUE (*dll_rb_define_module) (const char*);
238static void (*dll_rb_define_module_function) (VALUE,const char*,VALUE(*)(),int);
239static void (*dll_rb_define_singleton_method) (VALUE,const char*,VALUE(*)(),int);
240static void (*dll_rb_define_virtual_variable) (const char*,VALUE(*)(),void(*)());
241static VALUE *dll_rb_stdout;
242static VALUE *dll_rb_eArgError;
243static VALUE *dll_rb_eIndexError;
244static VALUE *dll_rb_eRuntimeError;
245static VALUE *dll_rb_eStandardError;
246static VALUE (*dll_rb_eval_string_protect) (const char*, int*);
247static void (*dll_rb_global_variable) (VALUE*);
248static VALUE (*dll_rb_hash_aset) (VALUE, VALUE, VALUE);
249static VALUE (*dll_rb_hash_new) (void);
250static VALUE (*dll_rb_inspect) (VALUE);
251static VALUE (*dll_rb_int2inum) (long);
252static VALUE (*dll_rb_int2inum) (long);
253static VALUE (*dll_rb_lastline_get) (void);
254static void (*dll_rb_lastline_set) (VALUE);
255static void (*dll_rb_load_protect) (VALUE, int, int*);
256static long (*dll_rb_num2long) (VALUE);
257static unsigned long (*dll_rb_num2ulong) (VALUE);
258static VALUE (*dll_rb_obj_alloc) (VALUE);
259static VALUE (*dll_rb_obj_as_string) (VALUE);
260static VALUE (*dll_rb_obj_id) (VALUE);
261static void (*dll_rb_raise) (VALUE, const char*, ...);
262static char *(*dll_rb_str2cstr) (VALUE,int*);
263static VALUE (*dll_rb_str_cat) (VALUE, const char*, long);
264static VALUE (*dll_rb_str_concat) (VALUE, VALUE);
265static VALUE (*dll_rb_str_new) (const char*, long);
266#ifdef need_rb_str_new_cstr
267/* Ruby may #define rb_str_new2 to use rb_str_new_cstr. */
268static VALUE (*dll_rb_str_new_cstr) (const char*);
269#else
270static VALUE (*dll_rb_str_new2) (const char*);
271#endif
272#ifdef RUBY19_OR_LATER
273static VALUE (*dll_rb_errinfo) (void);
274#else
275static VALUE *dll_ruby_errinfo;
276#endif
277static void (*dll_ruby_init) (void);
278static void (*dll_ruby_init_loadpath) (void);
279static void (*dll_NtInitialize) (int*, char***);
280#if defined(DYNAMIC_RUBY_VER) && DYNAMIC_RUBY_VER >= 18
281static char * (*dll_rb_string_value_ptr) (volatile VALUE*);
282static VALUE (*dll_rb_float_new) (double);
283static VALUE (*dll_rb_ary_new) (void);
284static VALUE (*dll_rb_ary_push) (VALUE, VALUE);
285#endif
286#ifdef RUBY19_OR_LATER
287static VALUE (*dll_rb_int2big)(SIGNED_VALUE);
288#endif
289#if defined(DYNAMIC_RUBY_VER) && DYNAMIC_RUBY_VER >= 18
290static int (*dll_rb_w32_snprintf)(char*, size_t, const char*, ...);
291#endif
292
293#ifdef RUBY19_OR_LATER
294static void (*dll_ruby_script) (const char*);
295static int (*dll_rb_enc_find_index) (const char*);
296static rb_encoding* (*dll_rb_enc_find) (const char*);
297static VALUE (*dll_rb_enc_str_new) (const char*, long, rb_encoding*);
298static VALUE (*dll_rb_sprintf) (const char*, ...);
299static void (*ruby_init_stack)(VALUE*);
300#endif
301
302#ifdef __APPLE__
303static unsigned long (*dll_rb_num2uint)(VALUE);
304static long (*dll_rb_num2int)(VALUE);
305static long (*dll_rb_fix2int)(VALUE);
306#endif
307
308#ifdef RUBY19_OR_LATER
309SIGNED_VALUE rb_num2long_stub(VALUE x)
310{
311    return dll_rb_num2long(x);
312}
313VALUE rb_int2big_stub(SIGNED_VALUE x)
314{
315    return dll_rb_int2big(x);
316}
317#endif
318
319static HINSTANCE hinstRuby = 0; /* Instance of ruby.dll */
320
321/*
322 * Table of name to function pointer of ruby.
323 */
324#define RUBY_PROC FARPROC
325static struct
326{
327    char *name;
328    RUBY_PROC *ptr;
329} ruby_funcname_table[] =
330{
331    {"rb_assoc_new", (RUBY_PROC*)&dll_rb_assoc_new},
332    {"rb_cFalseClass", (RUBY_PROC*)&dll_rb_cFalseClass},
333    {"rb_cFixnum", (RUBY_PROC*)&dll_rb_cFixnum},
334    {"rb_cNilClass", (RUBY_PROC*)&dll_rb_cNilClass},
335    {"rb_cObject", (RUBY_PROC*)&dll_rb_cObject},
336    {"rb_cSymbol", (RUBY_PROC*)&dll_rb_cSymbol},
337    {"rb_cTrueClass", (RUBY_PROC*)&dll_rb_cTrueClass},
338    {"rb_check_type", (RUBY_PROC*)&dll_rb_check_type},
339    {"rb_class_path", (RUBY_PROC*)&dll_rb_class_path},
340    {"rb_data_object_alloc", (RUBY_PROC*)&dll_rb_data_object_alloc},
341    {"rb_define_class_under", (RUBY_PROC*)&dll_rb_define_class_under},
342    {"rb_define_const", (RUBY_PROC*)&dll_rb_define_const},
343    {"rb_define_global_function", (RUBY_PROC*)&dll_rb_define_global_function},
344    {"rb_define_method", (RUBY_PROC*)&dll_rb_define_method},
345    {"rb_define_module", (RUBY_PROC*)&dll_rb_define_module},
346    {"rb_define_module_function", (RUBY_PROC*)&dll_rb_define_module_function},
347    {"rb_define_singleton_method", (RUBY_PROC*)&dll_rb_define_singleton_method},
348    {"rb_define_virtual_variable", (RUBY_PROC*)&dll_rb_define_virtual_variable},
349    {"rb_stdout", (RUBY_PROC*)&dll_rb_stdout},
350    {"rb_eArgError", (RUBY_PROC*)&dll_rb_eArgError},
351    {"rb_eIndexError", (RUBY_PROC*)&dll_rb_eIndexError},
352    {"rb_eRuntimeError", (RUBY_PROC*)&dll_rb_eRuntimeError},
353    {"rb_eStandardError", (RUBY_PROC*)&dll_rb_eStandardError},
354    {"rb_eval_string_protect", (RUBY_PROC*)&dll_rb_eval_string_protect},
355    {"rb_global_variable", (RUBY_PROC*)&dll_rb_global_variable},
356    {"rb_hash_aset", (RUBY_PROC*)&dll_rb_hash_aset},
357    {"rb_hash_new", (RUBY_PROC*)&dll_rb_hash_new},
358    {"rb_inspect", (RUBY_PROC*)&dll_rb_inspect},
359    {"rb_int2inum", (RUBY_PROC*)&dll_rb_int2inum},
360    {"rb_lastline_get", (RUBY_PROC*)&dll_rb_lastline_get},
361    {"rb_lastline_set", (RUBY_PROC*)&dll_rb_lastline_set},
362    {"rb_load_protect", (RUBY_PROC*)&dll_rb_load_protect},
363    {"rb_num2long", (RUBY_PROC*)&dll_rb_num2long},
364    {"rb_num2ulong", (RUBY_PROC*)&dll_rb_num2ulong},
365    {"rb_obj_alloc", (RUBY_PROC*)&dll_rb_obj_alloc},
366    {"rb_obj_as_string", (RUBY_PROC*)&dll_rb_obj_as_string},
367    {"rb_obj_id", (RUBY_PROC*)&dll_rb_obj_id},
368    {"rb_raise", (RUBY_PROC*)&dll_rb_raise},
369    {"rb_str2cstr", (RUBY_PROC*)&dll_rb_str2cstr},
370    {"rb_str_cat", (RUBY_PROC*)&dll_rb_str_cat},
371    {"rb_str_concat", (RUBY_PROC*)&dll_rb_str_concat},
372    {"rb_str_new", (RUBY_PROC*)&dll_rb_str_new},
373#ifdef need_rb_str_new_cstr
374    {"rb_str_new_cstr", (RUBY_PROC*)&dll_rb_str_new_cstr},
375#else
376    {"rb_str_new2", (RUBY_PROC*)&dll_rb_str_new2},
377#endif
378#ifdef RUBY19_OR_LATER
379    {"rb_errinfo", (RUBY_PROC*)&dll_rb_errinfo},
380#else
381    {"ruby_errinfo", (RUBY_PROC*)&dll_ruby_errinfo},
382#endif
383    {"ruby_init", (RUBY_PROC*)&dll_ruby_init},
384    {"ruby_init_loadpath", (RUBY_PROC*)&dll_ruby_init_loadpath},
385#if defined(_WIN32)
386    {
387#if defined(DYNAMIC_RUBY_VER) && DYNAMIC_RUBY_VER < 19
388    "NtInitialize",
389#else
390    "ruby_sysinit",
391#endif
392			(RUBY_PROC*)&dll_NtInitialize},
393#if defined(DYNAMIC_RUBY_VER) && DYNAMIC_RUBY_VER >= 18
394    {"rb_w32_snprintf", (RUBY_PROC*)&dll_rb_w32_snprintf},
395#endif
396#endif
397#if defined(DYNAMIC_RUBY_VER) && DYNAMIC_RUBY_VER >= 18
398    {"rb_string_value_ptr", (RUBY_PROC*)&dll_rb_string_value_ptr},
399    {"rb_float_new", (RUBY_PROC*)&dll_rb_float_new},
400    {"rb_ary_new", (RUBY_PROC*)&dll_rb_ary_new},
401    {"rb_ary_push", (RUBY_PROC*)&dll_rb_ary_push},
402#endif
403#ifdef RUBY19_OR_LATER
404    {"rb_int2big", (RUBY_PROC*)&dll_rb_int2big},
405    {"ruby_script", (RUBY_PROC*)&dll_ruby_script},
406    {"rb_enc_find_index", (RUBY_PROC*)&dll_rb_enc_find_index},
407    {"rb_enc_find", (RUBY_PROC*)&dll_rb_enc_find},
408    {"rb_enc_str_new", (RUBY_PROC*)&dll_rb_enc_str_new},
409    {"rb_sprintf", (RUBY_PROC*)&dll_rb_sprintf},
410    {"ruby_init_stack", (RUBY_PROC*)&dll_ruby_init_stack},
411#endif
412#ifdef __APPLE__
413    {"rb_num2uint", (RUBY_PROC*)&dll_rb_num2uint},
414    {"rb_num2int", (RUBY_PROC*)&dll_rb_num2int},
415    {"rb_fix2int", (RUBY_PROC*)&dll_rb_fix2int},
416#endif
417    {"", NULL},
418};
419
420/*
421 * Free ruby.dll
422 */
423    static void
424end_dynamic_ruby()
425{
426    if (hinstRuby)
427    {
428	FreeLibrary(hinstRuby);
429	hinstRuby = 0;
430    }
431}
432
433/*
434 * Load library and get all pointers.
435 * Parameter 'libname' provides name of DLL.
436 * Return OK or FAIL.
437 */
438    static int
439ruby_runtime_link_init(char *libname, int verbose)
440{
441    int i;
442
443    if (hinstRuby)
444	return OK;
445    hinstRuby = LoadLibrary(libname);
446    if (!hinstRuby)
447    {
448	if (verbose)
449	    EMSG2(_(e_loadlib), libname);
450	return FAIL;
451    }
452
453    for (i = 0; ruby_funcname_table[i].ptr; ++i)
454    {
455	if (!(*ruby_funcname_table[i].ptr = GetProcAddress(hinstRuby,
456			ruby_funcname_table[i].name)))
457	{
458	    FreeLibrary(hinstRuby);
459	    hinstRuby = 0;
460	    if (verbose)
461		EMSG2(_(e_loadfunc), ruby_funcname_table[i].name);
462	    return FAIL;
463	}
464    }
465    return OK;
466}
467
468/*
469 * If ruby is enabled (there is installed ruby on Windows system) return TRUE,
470 * else FALSE.
471 */
472    int
473ruby_enabled(verbose)
474    int		verbose;
475{
476    return ruby_runtime_link_init(DYNAMIC_RUBY_DLL, verbose) == OK;
477}
478#endif /* defined(DYNAMIC_RUBY) || defined(PROTO) */
479
480    void
481ruby_end()
482{
483#ifdef DYNAMIC_RUBY
484    end_dynamic_ruby();
485#endif
486}
487
488void ex_ruby(exarg_T *eap)
489{
490    int state;
491    char *script = NULL;
492
493    script = (char *)script_get(eap, eap->arg);
494    if (!eap->skip && ensure_ruby_initialized())
495    {
496	if (script == NULL)
497	    rb_eval_string_protect((char *)eap->arg, &state);
498	else
499	    rb_eval_string_protect(script, &state);
500	if (state)
501	    error_print(state);
502    }
503    vim_free(script);
504}
505
506/*
507 *  In Ruby 1.9 or later, ruby String object has encoding.
508 *  conversion buffer string of vim to ruby String object using
509 *  VIM encoding option.
510 */
511    static VALUE
512vim_str2rb_enc_str(const char *s)
513{
514#ifdef RUBY19_OR_LATER
515    int isnum;
516    long lval;
517    char_u *sval;
518    rb_encoding *enc;
519
520    isnum = get_option_value((char_u *)"enc", &lval, &sval, 0);
521    if (isnum == 0)
522    {
523	enc = rb_enc_find((char *)sval);
524	vim_free(sval);
525	if (enc) {
526	    return rb_enc_str_new(s, strlen(s), enc);
527	}
528    }
529#endif
530    return rb_str_new2(s);
531}
532
533    static VALUE
534eval_enc_string_protect(const char *str, int *state)
535{
536#ifdef RUBY19_OR_LATER
537    int isnum;
538    long lval;
539    char_u *sval;
540    rb_encoding *enc;
541    VALUE v;
542
543    isnum = get_option_value((char_u *)"enc", &lval, &sval, 0);
544    if (isnum == 0)
545    {
546	enc = rb_enc_find((char *)sval);
547	vim_free(sval);
548	if (enc)
549	{
550	    v = rb_sprintf("#-*- coding:%s -*-\n%s", rb_enc_name(enc), str);
551	    return rb_eval_string_protect(StringValuePtr(v), state);
552	}
553    }
554#endif
555    return rb_eval_string_protect(str, state);
556}
557
558void ex_rubydo(exarg_T *eap)
559{
560    int state;
561    linenr_T i;
562
563    if (ensure_ruby_initialized())
564    {
565	if (u_save(eap->line1 - 1, eap->line2 + 1) != OK)
566	    return;
567	for (i = eap->line1; i <= eap->line2; i++) {
568	    VALUE line, oldline;
569
570	    line = oldline = vim_str2rb_enc_str((char *)ml_get(i));
571	    rb_lastline_set(line);
572	    eval_enc_string_protect((char *) eap->arg, &state);
573	    if (state) {
574		error_print(state);
575		break;
576	    }
577	    line = rb_lastline_get();
578	    if (!NIL_P(line)) {
579		if (TYPE(line) != T_STRING) {
580		    EMSG(_("E265: $_ must be an instance of String"));
581		    return;
582		}
583		ml_replace(i, (char_u *) StringValuePtr(line), 1);
584		changed();
585#ifdef SYNTAX_HL
586		syn_changed(i); /* recompute syntax hl. for this line */
587#endif
588	    }
589	}
590	check_cursor();
591	update_curbuf(NOT_VALID);
592    }
593}
594
595void ex_rubyfile(exarg_T *eap)
596{
597    int state;
598
599    if (ensure_ruby_initialized())
600    {
601	rb_load_protect(rb_str_new2((char *) eap->arg), 0, &state);
602	if (state) error_print(state);
603    }
604}
605
606void ruby_buffer_free(buf_T *buf)
607{
608    if (buf->b_ruby_ref)
609    {
610	rb_hash_aset(objtbl, rb_obj_id((VALUE) buf->b_ruby_ref), Qnil);
611	RDATA(buf->b_ruby_ref)->data = NULL;
612    }
613}
614
615void ruby_window_free(win_T *win)
616{
617    if (win->w_ruby_ref)
618    {
619	rb_hash_aset(objtbl, rb_obj_id((VALUE) win->w_ruby_ref), Qnil);
620	RDATA(win->w_ruby_ref)->data = NULL;
621    }
622}
623
624static int ensure_ruby_initialized(void)
625{
626    if (!ruby_initialized)
627    {
628#ifdef DYNAMIC_RUBY
629	if (ruby_enabled(TRUE))
630	{
631#endif
632#ifdef _WIN32
633	    /* suggested by Ariya Mizutani */
634	    int argc = 1;
635	    char *argv[] = {"gvim.exe"};
636	    NtInitialize(&argc, &argv);
637#endif
638	    {
639#ifdef RUBY19_OR_LATER
640		RUBY_INIT_STACK;
641#endif
642		ruby_init();
643	    }
644#ifdef RUBY19_OR_LATER
645	    ruby_script("vim-ruby");
646#endif
647	    ruby_init_loadpath();
648	    ruby_io_init();
649#ifdef RUBY19_OR_LATER
650	    rb_enc_find_index("encdb");
651#endif
652	    ruby_vim_init();
653	    ruby_initialized = 1;
654#ifdef DYNAMIC_RUBY
655	}
656	else
657	{
658	    EMSG(_("E266: Sorry, this command is disabled, the Ruby library could not be loaded."));
659	    return 0;
660	}
661#endif
662    }
663    return ruby_initialized;
664}
665
666static void error_print(int state)
667{
668#ifndef DYNAMIC_RUBY
669#if !(defined(RUBY_VERSION) && RUBY_VERSION >= 19) \
670    && !(defined(DYNAMIC_RUBY_VER) && DYNAMIC_RUBY_VER >= 19)
671    RUBYEXTERN VALUE ruby_errinfo;
672#endif
673#endif
674    VALUE eclass;
675    VALUE einfo;
676    char buff[BUFSIZ];
677
678#define TAG_RETURN	0x1
679#define TAG_BREAK	0x2
680#define TAG_NEXT	0x3
681#define TAG_RETRY	0x4
682#define TAG_REDO	0x5
683#define TAG_RAISE	0x6
684#define TAG_THROW	0x7
685#define TAG_FATAL	0x8
686#define TAG_MASK	0xf
687
688    switch (state) {
689    case TAG_RETURN:
690	EMSG(_("E267: unexpected return"));
691	break;
692    case TAG_NEXT:
693	EMSG(_("E268: unexpected next"));
694	break;
695    case TAG_BREAK:
696	EMSG(_("E269: unexpected break"));
697	break;
698    case TAG_REDO:
699	EMSG(_("E270: unexpected redo"));
700	break;
701    case TAG_RETRY:
702	EMSG(_("E271: retry outside of rescue clause"));
703	break;
704    case TAG_RAISE:
705    case TAG_FATAL:
706#ifdef RUBY19_OR_LATER
707	eclass = CLASS_OF(rb_errinfo());
708	einfo = rb_obj_as_string(rb_errinfo());
709#else
710	eclass = CLASS_OF(ruby_errinfo);
711	einfo = rb_obj_as_string(ruby_errinfo);
712#endif
713	if (eclass == rb_eRuntimeError && RSTRING_LEN(einfo) == 0) {
714	    EMSG(_("E272: unhandled exception"));
715	}
716	else {
717	    VALUE epath;
718	    char *p;
719
720	    epath = rb_class_path(eclass);
721	    vim_snprintf(buff, BUFSIZ, "%s: %s",
722		     RSTRING_PTR(epath), RSTRING_PTR(einfo));
723	    p = strchr(buff, '\n');
724	    if (p) *p = '\0';
725	    EMSG(buff);
726	}
727	break;
728    default:
729	vim_snprintf(buff, BUFSIZ, _("E273: unknown longjmp status %d"), state);
730	EMSG(buff);
731	break;
732    }
733}
734
735static VALUE vim_message(VALUE self UNUSED, VALUE str)
736{
737    char *buff, *p;
738
739    str = rb_obj_as_string(str);
740    buff = ALLOCA_N(char, RSTRING_LEN(str));
741    strcpy(buff, RSTRING_PTR(str));
742    p = strchr(buff, '\n');
743    if (p) *p = '\0';
744    MSG(buff);
745    return Qnil;
746}
747
748static VALUE vim_set_option(VALUE self UNUSED, VALUE str)
749{
750    do_set((char_u *)StringValuePtr(str), 0);
751    update_screen(NOT_VALID);
752    return Qnil;
753}
754
755static VALUE vim_command(VALUE self UNUSED, VALUE str)
756{
757    do_cmdline_cmd((char_u *)StringValuePtr(str));
758    return Qnil;
759}
760
761#ifdef FEAT_EVAL
762static VALUE vim_to_ruby(typval_T *tv)
763{
764    VALUE result = Qnil;
765
766    if (tv->v_type == VAR_STRING)
767    {
768	result = rb_str_new2(tv->vval.v_string == NULL
769					  ? "" : (char *)(tv->vval.v_string));
770    }
771    else if (tv->v_type == VAR_NUMBER)
772    {
773	result = INT2NUM(tv->vval.v_number);
774    }
775# ifdef FEAT_FLOAT
776    else if (tv->v_type == VAR_FLOAT)
777    {
778	result = rb_float_new(tv->vval.v_float);
779    }
780# endif
781    else if (tv->v_type == VAR_LIST)
782    {
783	list_T      *list = tv->vval.v_list;
784	listitem_T  *curr;
785
786	result = rb_ary_new();
787
788	if (list != NULL)
789	{
790	    for (curr = list->lv_first; curr != NULL; curr = curr->li_next)
791	    {
792		rb_ary_push(result, vim_to_ruby(&curr->li_tv));
793	    }
794	}
795    }
796    else if (tv->v_type == VAR_DICT)
797    {
798	result = rb_hash_new();
799
800	if (tv->vval.v_dict != NULL)
801	{
802	    hashtab_T   *ht = &tv->vval.v_dict->dv_hashtab;
803	    long_u      todo = ht->ht_used;
804	    hashitem_T  *hi;
805	    dictitem_T  *di;
806
807	    for (hi = ht->ht_array; todo > 0; ++hi)
808	    {
809		if (!HASHITEM_EMPTY(hi))
810		{
811		    --todo;
812
813		    di = dict_lookup(hi);
814		    rb_hash_aset(result, rb_str_new2((char *)hi->hi_key),
815						     vim_to_ruby(&di->di_tv));
816		}
817	    }
818	}
819    } /* else return Qnil; */
820
821    return result;
822}
823#endif
824
825static VALUE vim_evaluate(VALUE self UNUSED, VALUE str)
826{
827#ifdef FEAT_EVAL
828    typval_T    *tv;
829    VALUE       result;
830
831    tv = eval_expr((char_u *)StringValuePtr(str), NULL);
832    if (tv == NULL)
833    {
834	return Qnil;
835    }
836    result = vim_to_ruby(tv);
837
838    free_tv(tv);
839
840    return result;
841#else
842    return Qnil;
843#endif
844}
845
846static VALUE buffer_new(buf_T *buf)
847{
848    if (buf->b_ruby_ref)
849    {
850	return (VALUE) buf->b_ruby_ref;
851    }
852    else
853    {
854	VALUE obj = Data_Wrap_Struct(cBuffer, 0, 0, buf);
855	buf->b_ruby_ref = (void *) obj;
856	rb_hash_aset(objtbl, rb_obj_id(obj), obj);
857	return obj;
858    }
859}
860
861static buf_T *get_buf(VALUE obj)
862{
863    buf_T *buf;
864
865    Data_Get_Struct(obj, buf_T, buf);
866    if (buf == NULL)
867	rb_raise(eDeletedBufferError, "attempt to refer to deleted buffer");
868    return buf;
869}
870
871static VALUE buffer_s_current()
872{
873    return buffer_new(curbuf);
874}
875
876static VALUE buffer_s_count()
877{
878    buf_T *b;
879    int n = 0;
880
881    for (b = firstbuf; b != NULL; b = b->b_next)
882    {
883	/*  Deleted buffers should not be counted
884	 *    SegPhault - 01/07/05 */
885	if (b->b_p_bl)
886	    n++;
887    }
888
889    return INT2NUM(n);
890}
891
892static VALUE buffer_s_aref(VALUE self UNUSED, VALUE num)
893{
894    buf_T *b;
895    int n = NUM2INT(num);
896
897    for (b = firstbuf; b != NULL; b = b->b_next)
898    {
899	/*  Deleted buffers should not be counted
900	 *    SegPhault - 01/07/05 */
901	if (!b->b_p_bl)
902	    continue;
903
904	if (n == 0)
905	    return buffer_new(b);
906
907	n--;
908    }
909    return Qnil;
910}
911
912static VALUE buffer_name(VALUE self)
913{
914    buf_T *buf = get_buf(self);
915
916    return buf->b_ffname ? rb_str_new2((char *)buf->b_ffname) : Qnil;
917}
918
919static VALUE buffer_number(VALUE self)
920{
921    buf_T *buf = get_buf(self);
922
923    return INT2NUM(buf->b_fnum);
924}
925
926static VALUE buffer_count(VALUE self)
927{
928    buf_T *buf = get_buf(self);
929
930    return INT2NUM(buf->b_ml.ml_line_count);
931}
932
933static VALUE get_buffer_line(buf_T *buf, linenr_T n)
934{
935    if (n > 0 && n <= buf->b_ml.ml_line_count)
936    {
937	char *line = (char *)ml_get_buf(buf, n, FALSE);
938	return line ? vim_str2rb_enc_str(line) : Qnil;
939    }
940    rb_raise(rb_eIndexError, "line number %ld out of range", (long)n);
941#ifndef __GNUC__
942    return Qnil; /* For stop warning */
943#endif
944}
945
946static VALUE buffer_aref(VALUE self, VALUE num)
947{
948    buf_T *buf = get_buf(self);
949
950    if (buf != NULL)
951	return get_buffer_line(buf, (linenr_T)NUM2LONG(num));
952    return Qnil; /* For stop warning */
953}
954
955static VALUE set_buffer_line(buf_T *buf, linenr_T n, VALUE str)
956{
957    char	*line = StringValuePtr(str);
958    aco_save_T	aco;
959
960    if (n > 0 && n <= buf->b_ml.ml_line_count && line != NULL)
961    {
962	/* set curwin/curbuf for "buf" and save some things */
963	aucmd_prepbuf(&aco, buf);
964
965	if (u_savesub(n) == OK) {
966	    ml_replace(n, (char_u *)line, TRUE);
967	    changed();
968#ifdef SYNTAX_HL
969	    syn_changed(n); /* recompute syntax hl. for this line */
970#endif
971	}
972
973	/* restore curwin/curbuf and a few other things */
974	aucmd_restbuf(&aco);
975	/* Careful: autocommands may have made "buf" invalid! */
976
977	update_curbuf(NOT_VALID);
978    }
979    else
980    {
981	rb_raise(rb_eIndexError, "line number %ld out of range", (long)n);
982#ifndef __GNUC__
983	return Qnil; /* For stop warning */
984#endif
985    }
986    return str;
987}
988
989static VALUE buffer_aset(VALUE self, VALUE num, VALUE str)
990{
991    buf_T *buf = get_buf(self);
992
993    if (buf != NULL)
994	return set_buffer_line(buf, (linenr_T)NUM2LONG(num), str);
995    return str;
996}
997
998static VALUE buffer_delete(VALUE self, VALUE num)
999{
1000    buf_T	*buf = get_buf(self);
1001    long	n = NUM2LONG(num);
1002    aco_save_T	aco;
1003
1004    if (n > 0 && n <= buf->b_ml.ml_line_count)
1005    {
1006	/* set curwin/curbuf for "buf" and save some things */
1007	aucmd_prepbuf(&aco, buf);
1008
1009	if (u_savedel(n, 1) == OK) {
1010	    ml_delete(n, 0);
1011
1012	    /* Changes to non-active buffers should properly refresh
1013	     *   SegPhault - 01/09/05 */
1014	    deleted_lines_mark(n, 1L);
1015
1016	    changed();
1017	}
1018
1019	/* restore curwin/curbuf and a few other things */
1020	aucmd_restbuf(&aco);
1021	/* Careful: autocommands may have made "buf" invalid! */
1022
1023	update_curbuf(NOT_VALID);
1024    }
1025    else
1026    {
1027	rb_raise(rb_eIndexError, "line number %ld out of range", n);
1028    }
1029    return Qnil;
1030}
1031
1032static VALUE buffer_append(VALUE self, VALUE num, VALUE str)
1033{
1034    buf_T	*buf = get_buf(self);
1035    char	*line = StringValuePtr(str);
1036    long	n = NUM2LONG(num);
1037    aco_save_T	aco;
1038
1039    if (line == NULL) {
1040	rb_raise(rb_eIndexError, "NULL line");
1041    }
1042    else if (n >= 0 && n <= buf->b_ml.ml_line_count)
1043    {
1044	/* set curwin/curbuf for "buf" and save some things */
1045	aucmd_prepbuf(&aco, buf);
1046
1047	if (u_inssub(n + 1) == OK) {
1048	    ml_append(n, (char_u *) line, (colnr_T) 0, FALSE);
1049
1050	    /*  Changes to non-active buffers should properly refresh screen
1051	     *    SegPhault - 12/20/04 */
1052	    appended_lines_mark(n, 1L);
1053
1054	    changed();
1055	}
1056
1057	/* restore curwin/curbuf and a few other things */
1058	aucmd_restbuf(&aco);
1059	/* Careful: autocommands may have made "buf" invalid! */
1060
1061	update_curbuf(NOT_VALID);
1062    }
1063    else {
1064	rb_raise(rb_eIndexError, "line number %ld out of range", n);
1065    }
1066    return str;
1067}
1068
1069static VALUE window_new(win_T *win)
1070{
1071    if (win->w_ruby_ref)
1072    {
1073	return (VALUE) win->w_ruby_ref;
1074    }
1075    else
1076    {
1077	VALUE obj = Data_Wrap_Struct(cVimWindow, 0, 0, win);
1078	win->w_ruby_ref = (void *) obj;
1079	rb_hash_aset(objtbl, rb_obj_id(obj), obj);
1080	return obj;
1081    }
1082}
1083
1084static win_T *get_win(VALUE obj)
1085{
1086    win_T *win;
1087
1088    Data_Get_Struct(obj, win_T, win);
1089    if (win == NULL)
1090	rb_raise(eDeletedWindowError, "attempt to refer to deleted window");
1091    return win;
1092}
1093
1094static VALUE window_s_current()
1095{
1096    return window_new(curwin);
1097}
1098
1099/*
1100 * Added line manipulation functions
1101 *    SegPhault - 03/07/05
1102 */
1103static VALUE line_s_current()
1104{
1105    return get_buffer_line(curbuf, curwin->w_cursor.lnum);
1106}
1107
1108static VALUE set_current_line(VALUE self UNUSED, VALUE str)
1109{
1110    return set_buffer_line(curbuf, curwin->w_cursor.lnum, str);
1111}
1112
1113static VALUE current_line_number()
1114{
1115    return INT2FIX((int)curwin->w_cursor.lnum);
1116}
1117
1118
1119
1120static VALUE window_s_count()
1121{
1122#ifdef FEAT_WINDOWS
1123    win_T	*w;
1124    int n = 0;
1125
1126    for (w = firstwin; w != NULL; w = w->w_next)
1127	n++;
1128    return INT2NUM(n);
1129#else
1130    return INT2NUM(1);
1131#endif
1132}
1133
1134static VALUE window_s_aref(VALUE self UNUSED, VALUE num)
1135{
1136    win_T *w;
1137    int n = NUM2INT(num);
1138
1139#ifndef FEAT_WINDOWS
1140    w = curwin;
1141#else
1142    for (w = firstwin; w != NULL; w = w->w_next, --n)
1143#endif
1144	if (n == 0)
1145	    return window_new(w);
1146    return Qnil;
1147}
1148
1149static VALUE window_buffer(VALUE self)
1150{
1151    win_T *win = get_win(self);
1152
1153    return buffer_new(win->w_buffer);
1154}
1155
1156static VALUE window_height(VALUE self)
1157{
1158    win_T *win = get_win(self);
1159
1160    return INT2NUM(win->w_height);
1161}
1162
1163static VALUE window_set_height(VALUE self, VALUE height)
1164{
1165    win_T *win = get_win(self);
1166    win_T *savewin = curwin;
1167
1168    curwin = win;
1169    win_setheight(NUM2INT(height));
1170    curwin = savewin;
1171    return height;
1172}
1173
1174static VALUE window_width(VALUE self)
1175{
1176    win_T *win = get_win(self);
1177
1178    return INT2NUM(win->w_width);
1179}
1180
1181static VALUE window_set_width(VALUE self, VALUE width)
1182{
1183    win_T *win = get_win(self);
1184    win_T *savewin = curwin;
1185
1186    curwin = win;
1187    win_setwidth(NUM2INT(width));
1188    curwin = savewin;
1189    return width;
1190}
1191
1192static VALUE window_cursor(VALUE self)
1193{
1194    win_T *win = get_win(self);
1195
1196    return rb_assoc_new(INT2NUM(win->w_cursor.lnum), INT2NUM(win->w_cursor.col));
1197}
1198
1199static VALUE window_set_cursor(VALUE self, VALUE pos)
1200{
1201    VALUE lnum, col;
1202    win_T *win = get_win(self);
1203
1204    Check_Type(pos, T_ARRAY);
1205    if (RARRAY_LEN(pos) != 2)
1206	rb_raise(rb_eArgError, "array length must be 2");
1207    lnum = RARRAY_PTR(pos)[0];
1208    col = RARRAY_PTR(pos)[1];
1209    win->w_cursor.lnum = NUM2LONG(lnum);
1210    win->w_cursor.col = NUM2UINT(col);
1211    check_cursor();		    /* put cursor on an existing line */
1212    update_screen(NOT_VALID);
1213    return Qnil;
1214}
1215
1216static VALUE f_p(int argc, VALUE *argv, VALUE self UNUSED)
1217{
1218    int i;
1219    VALUE str = rb_str_new("", 0);
1220
1221    for (i = 0; i < argc; i++) {
1222	if (i > 0) rb_str_cat(str, ", ", 2);
1223	rb_str_concat(str, rb_inspect(argv[i]));
1224    }
1225    MSG(RSTRING_PTR(str));
1226    return Qnil;
1227}
1228
1229static void ruby_io_init(void)
1230{
1231#ifndef DYNAMIC_RUBY
1232    RUBYEXTERN VALUE rb_stdout;
1233#endif
1234
1235    rb_stdout = rb_obj_alloc(rb_cObject);
1236    rb_define_singleton_method(rb_stdout, "write", vim_message, 1);
1237    rb_define_global_function("p", f_p, -1);
1238}
1239
1240static void ruby_vim_init(void)
1241{
1242    objtbl = rb_hash_new();
1243    rb_global_variable(&objtbl);
1244
1245    /* The Vim module used to be called "VIM", but "Vim" is better.  Make an
1246     * alias "VIM" for backwards compatiblity. */
1247    mVIM = rb_define_module("Vim");
1248    rb_define_const(rb_cObject, "VIM", mVIM);
1249    rb_define_const(mVIM, "VERSION_MAJOR", INT2NUM(VIM_VERSION_MAJOR));
1250    rb_define_const(mVIM, "VERSION_MINOR", INT2NUM(VIM_VERSION_MINOR));
1251    rb_define_const(mVIM, "VERSION_BUILD", INT2NUM(VIM_VERSION_BUILD));
1252    rb_define_const(mVIM, "VERSION_PATCHLEVEL", INT2NUM(VIM_VERSION_PATCHLEVEL));
1253    rb_define_const(mVIM, "VERSION_SHORT", rb_str_new2(VIM_VERSION_SHORT));
1254    rb_define_const(mVIM, "VERSION_MEDIUM", rb_str_new2(VIM_VERSION_MEDIUM));
1255    rb_define_const(mVIM, "VERSION_LONG", rb_str_new2(VIM_VERSION_LONG));
1256    rb_define_const(mVIM, "VERSION_LONG_DATE", rb_str_new2(VIM_VERSION_LONG_DATE));
1257    rb_define_module_function(mVIM, "message", vim_message, 1);
1258    rb_define_module_function(mVIM, "set_option", vim_set_option, 1);
1259    rb_define_module_function(mVIM, "command", vim_command, 1);
1260    rb_define_module_function(mVIM, "evaluate", vim_evaluate, 1);
1261
1262    eDeletedBufferError = rb_define_class_under(mVIM, "DeletedBufferError",
1263						rb_eStandardError);
1264    eDeletedWindowError = rb_define_class_under(mVIM, "DeletedWindowError",
1265						rb_eStandardError);
1266
1267    cBuffer = rb_define_class_under(mVIM, "Buffer", rb_cObject);
1268    rb_define_singleton_method(cBuffer, "current", buffer_s_current, 0);
1269    rb_define_singleton_method(cBuffer, "count", buffer_s_count, 0);
1270    rb_define_singleton_method(cBuffer, "[]", buffer_s_aref, 1);
1271    rb_define_method(cBuffer, "name", buffer_name, 0);
1272    rb_define_method(cBuffer, "number", buffer_number, 0);
1273    rb_define_method(cBuffer, "count", buffer_count, 0);
1274    rb_define_method(cBuffer, "length", buffer_count, 0);
1275    rb_define_method(cBuffer, "[]", buffer_aref, 1);
1276    rb_define_method(cBuffer, "[]=", buffer_aset, 2);
1277    rb_define_method(cBuffer, "delete", buffer_delete, 1);
1278    rb_define_method(cBuffer, "append", buffer_append, 2);
1279
1280    /* Added line manipulation functions
1281     *   SegPhault - 03/07/05 */
1282    rb_define_method(cBuffer, "line_number", current_line_number, 0);
1283    rb_define_method(cBuffer, "line", line_s_current, 0);
1284    rb_define_method(cBuffer, "line=", set_current_line, 1);
1285
1286
1287    cVimWindow = rb_define_class_under(mVIM, "Window", rb_cObject);
1288    rb_define_singleton_method(cVimWindow, "current", window_s_current, 0);
1289    rb_define_singleton_method(cVimWindow, "count", window_s_count, 0);
1290    rb_define_singleton_method(cVimWindow, "[]", window_s_aref, 1);
1291    rb_define_method(cVimWindow, "buffer", window_buffer, 0);
1292    rb_define_method(cVimWindow, "height", window_height, 0);
1293    rb_define_method(cVimWindow, "height=", window_set_height, 1);
1294    rb_define_method(cVimWindow, "width", window_width, 0);
1295    rb_define_method(cVimWindow, "width=", window_set_width, 1);
1296    rb_define_method(cVimWindow, "cursor", window_cursor, 0);
1297    rb_define_method(cVimWindow, "cursor=", window_set_cursor, 1);
1298
1299    rb_define_virtual_variable("$curbuf", buffer_s_current, 0);
1300    rb_define_virtual_variable("$curwin", window_s_current, 0);
1301}
1302