blob: 8dd2134313db175e03bb97ddac97bf394f572804 [file] [log] [blame]
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001/* vi:set ts=8 sts=4 sw=4:
2 *
Bram Moolenaar2e6aff32005-01-31 19:25:36 +00003 * MzScheme interface by Sergey Khorev <sergey.khorev@gmail.com>
Bram Moolenaar75676462013-01-30 14:55:42 +01004 * Based on work by Brent Fulgham <bfulgham@debian.org>
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005 * (Based on lots of help from Matthew Flatt)
6 *
7 * This consists of six parts:
8 * 1. MzScheme interpreter main program
9 * 2. Routines that handle the external interface between MzScheme and
10 * Vim.
11 * 3. MzScheme input/output handlers: writes output via [e]msg().
12 * 4. Implementation of the Vim Features for MzScheme
13 * 5. Vim Window-related Manipulation Functions.
14 * 6. Vim Buffer-related Manipulation Functions
15 *
16 * NOTES
17 * 1. Memory, allocated with scheme_malloc*, need not to be freed explicitly,
18 * garbage collector will do it self
19 * 2. Requires at least NORMAL features. I can't imagine why one may want
20 * to build with SMALL or TINY features but with MzScheme interface.
Bram Moolenaar9e70cf12009-05-26 20:59:55 +000021 * 3. I don't use K&R-style functions. Anyways, MzScheme headers are ANSI.
Bram Moolenaar325b7a22004-07-05 15:58:32 +000022 */
23
Bram Moolenaar325b7a22004-07-05 15:58:32 +000024#include "vim.h"
Bram Moolenaar049377e2007-05-12 15:32:12 +000025
Bram Moolenaar325b7a22004-07-05 15:58:32 +000026#include "if_mzsch.h"
27
Bram Moolenaar76b92b22006-03-24 22:46:53 +000028/* Only do the following when the feature is enabled. Needed for "make
29 * depend". */
30#if defined(FEAT_MZSCHEME) || defined(PROTO)
31
Bram Moolenaar325b7a22004-07-05 15:58:32 +000032/* Base data structures */
33#define SCHEME_VIMBUFFERP(obj) SAME_TYPE(SCHEME_TYPE(obj), mz_buffer_type)
34#define SCHEME_VIMWINDOWP(obj) SAME_TYPE(SCHEME_TYPE(obj), mz_window_type)
35
36typedef struct
37{
Bram Moolenaar9e70cf12009-05-26 20:59:55 +000038 Scheme_Object so;
Bram Moolenaar325b7a22004-07-05 15:58:32 +000039 buf_T *buf;
Bram Moolenaar325b7a22004-07-05 15:58:32 +000040} vim_mz_buffer;
41
42#define INVALID_BUFFER_VALUE ((buf_T *)(-1))
43
44typedef struct
45{
Bram Moolenaar9e70cf12009-05-26 20:59:55 +000046 Scheme_Object so;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +000047 win_T *win;
Bram Moolenaar325b7a22004-07-05 15:58:32 +000048} vim_mz_window;
49
50#define INVALID_WINDOW_VALUE ((win_T *)(-1))
51
52/*
53 * Prims that form MzScheme Vim interface
54 */
55typedef struct
56{
57 Scheme_Closed_Prim *prim;
58 char *name;
59 int mina; /* arity information */
60 int maxa;
61} Vim_Prim;
62
63typedef struct
64{
65 char *name;
66 Scheme_Object *port;
67} Port_Info;
68
Bram Moolenaar325b7a22004-07-05 15:58:32 +000069/*
70 *========================================================================
71 * Vim-Control Commands
72 *========================================================================
73 */
74/*
75 *========================================================================
76 * Utility functions for the vim/mzscheme interface
77 *========================================================================
78 */
Bram Moolenaar555b2802005-05-19 21:08:39 +000079#ifdef HAVE_SANDBOX
80static Scheme_Object *sandbox_file_guard(int, Scheme_Object **);
81static Scheme_Object *sandbox_network_guard(int, Scheme_Object **);
Bram Moolenaarc81e5e72007-05-05 18:24:42 +000082static void sandbox_check(void);
Bram Moolenaar555b2802005-05-19 21:08:39 +000083#endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +000084/* Buffer-related commands */
85static Scheme_Object *buffer_new(buf_T *buf);
86static Scheme_Object *get_buffer_by_name(void *, int, Scheme_Object **);
87static Scheme_Object *get_buffer_by_num(void *, int, Scheme_Object **);
88static Scheme_Object *get_buffer_count(void *, int, Scheme_Object **);
89static Scheme_Object *get_buffer_line(void *, int, Scheme_Object **);
90static Scheme_Object *get_buffer_line_list(void *, int, Scheme_Object **);
91static Scheme_Object *get_buffer_name(void *, int, Scheme_Object **);
92static Scheme_Object *get_buffer_num(void *, int, Scheme_Object **);
93static Scheme_Object *get_buffer_size(void *, int, Scheme_Object **);
94static Scheme_Object *get_curr_buffer(void *, int, Scheme_Object **);
95static Scheme_Object *get_next_buffer(void *, int, Scheme_Object **);
96static Scheme_Object *get_prev_buffer(void *, int, Scheme_Object **);
97static Scheme_Object *mzscheme_open_buffer(void *, int, Scheme_Object **);
98static Scheme_Object *set_buffer_line(void *, int, Scheme_Object **);
99static Scheme_Object *set_buffer_line_list(void *, int, Scheme_Object **);
100static Scheme_Object *insert_buffer_line_list(void *, int, Scheme_Object **);
101static Scheme_Object *get_range_start(void *, int, Scheme_Object **);
102static Scheme_Object *get_range_end(void *, int, Scheme_Object **);
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000103static vim_mz_buffer *get_vim_curr_buffer(void);
104
105/* Window-related commands */
106static Scheme_Object *window_new(win_T *win);
107static Scheme_Object *get_curr_win(void *, int, Scheme_Object **);
108static Scheme_Object *get_window_count(void *, int, Scheme_Object **);
109static Scheme_Object *get_window_by_num(void *, int, Scheme_Object **);
110static Scheme_Object *get_window_num(void *, int, Scheme_Object **);
111static Scheme_Object *get_window_buffer(void *, int, Scheme_Object **);
112static Scheme_Object *get_window_height(void *, int, Scheme_Object **);
113static Scheme_Object *set_window_height(void *, int, Scheme_Object **);
114#ifdef FEAT_VERTSPLIT
115static Scheme_Object *get_window_width(void *, int, Scheme_Object **);
116static Scheme_Object *set_window_width(void *, int, Scheme_Object **);
117#endif
118static Scheme_Object *get_cursor(void *, int, Scheme_Object **);
119static Scheme_Object *set_cursor(void *, int, Scheme_Object **);
120static Scheme_Object *get_window_list(void *, int, Scheme_Object **);
121static vim_mz_window *get_vim_curr_window(void);
122
123/* Vim-related commands */
124static Scheme_Object *mzscheme_beep(void *, int, Scheme_Object **);
125static Scheme_Object *get_option(void *, int, Scheme_Object **);
126static Scheme_Object *set_option(void *, int, Scheme_Object **);
127static Scheme_Object *vim_command(void *, int, Scheme_Object **);
128static Scheme_Object *vim_eval(void *, int, Scheme_Object **);
129static Scheme_Object *vim_bufferp(void *data, int, Scheme_Object **);
130static Scheme_Object *vim_windowp(void *data, int, Scheme_Object **);
131static Scheme_Object *vim_buffer_validp(void *data, int, Scheme_Object **);
132static Scheme_Object *vim_window_validp(void *data, int, Scheme_Object **);
133
134/*
135 *========================================================================
136 * Internal Function Prototypes
137 *========================================================================
138 */
139static int vim_error_check(void);
140static int do_mzscheme_command(exarg_T *, void *, Scheme_Closed_Prim *what);
141static void startup_mzscheme(void);
142static char *string_to_line(Scheme_Object *obj);
Bram Moolenaar75676462013-01-30 14:55:42 +0100143#if MZSCHEME_VERSION_MAJOR >= 500
144# define OUTPUT_LEN_TYPE intptr_t
145#else
146# define OUTPUT_LEN_TYPE long
147#endif
148static void do_output(char *mesg, OUTPUT_LEN_TYPE len);
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000149static void do_printf(char *format, ...);
150static void do_flush(void);
151static Scheme_Object *_apply_thunk_catch_exceptions(
152 Scheme_Object *, Scheme_Object **);
153static Scheme_Object *extract_exn_message(Scheme_Object *v);
154static Scheme_Object *do_eval(void *, int noargc, Scheme_Object **noargv);
155static Scheme_Object *do_load(void *, int noargc, Scheme_Object **noargv);
Bram Moolenaar9e70cf12009-05-26 20:59:55 +0000156static void register_vim_exn(void);
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000157static vim_mz_buffer *get_buffer_arg(const char *fname, int argnum,
158 int argc, Scheme_Object **argv);
159static vim_mz_window *get_window_arg(const char *fname, int argnum,
160 int argc, Scheme_Object **argv);
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000161static int line_in_range(linenr_T, buf_T *);
162static void check_line_range(linenr_T, buf_T *);
163static void mz_fix_cursor(int lo, int hi, int extra);
164
Bram Moolenaar9e70cf12009-05-26 20:59:55 +0000165static int eval_with_exn_handling(void *, Scheme_Closed_Prim *,
166 Scheme_Object **ret);
167static void make_modules(void);
168static void init_exn_catching_apply(void);
169static int mzscheme_env_main(Scheme_Env *env, int argc, char **argv);
170static int mzscheme_init(void);
171#ifdef FEAT_EVAL
Bram Moolenaar75676462013-01-30 14:55:42 +0100172static Scheme_Object *vim_to_mzscheme(typval_T *vim_value);
173static Scheme_Object *vim_to_mzscheme_impl(typval_T *vim_value, int depth,
Bram Moolenaar9e70cf12009-05-26 20:59:55 +0000174 Scheme_Hash_Table *visited);
Bram Moolenaar75676462013-01-30 14:55:42 +0100175static int mzscheme_to_vim(Scheme_Object *obj, typval_T *tv);
176static int mzscheme_to_vim_impl(Scheme_Object *obj, typval_T *tv, int depth,
Bram Moolenaar7e506b62010-01-19 15:55:06 +0100177 Scheme_Hash_Table *visited);
Bram Moolenaar75676462013-01-30 14:55:42 +0100178static Scheme_Object *vim_funcref(void *data, int argc, Scheme_Object **argv);
Bram Moolenaar9e70cf12009-05-26 20:59:55 +0000179#endif
180
181#ifdef MZ_PRECISE_GC
Bram Moolenaar64404472010-06-26 06:24:45 +0200182static int buffer_size_proc(void *obj UNUSED)
Bram Moolenaar9e70cf12009-05-26 20:59:55 +0000183{
184 return gcBYTES_TO_WORDS(sizeof(vim_mz_buffer));
185}
186static int buffer_mark_proc(void *obj)
187{
188 return buffer_size_proc(obj);
189}
190static int buffer_fixup_proc(void *obj)
191{
Bram Moolenaar75676462013-01-30 14:55:42 +0100192 /* apparently not needed as the object will be uncollectable while
193 * the buffer is alive
194 */
195 /*
196 vim_mz_buffer* buf = (vim_mz_buffer*) obj;
197 buf->buf->b_mzscheme_ref = GC_fixup_self(obj);
198 */
Bram Moolenaar9e70cf12009-05-26 20:59:55 +0000199 return buffer_size_proc(obj);
200}
Bram Moolenaar64404472010-06-26 06:24:45 +0200201static int window_size_proc(void *obj UNUSED)
Bram Moolenaar9e70cf12009-05-26 20:59:55 +0000202{
203 return gcBYTES_TO_WORDS(sizeof(vim_mz_window));
204}
205static int window_mark_proc(void *obj)
206{
207 return window_size_proc(obj);
208}
209static int window_fixup_proc(void *obj)
210{
Bram Moolenaar75676462013-01-30 14:55:42 +0100211 /* apparently not needed as the object will be uncollectable while
212 * the window is alive
213 */
214 /*
215 vim_mz_window* win = (vim_mz_window*) obj;
216 win->win->w_mzscheme_ref = GC_fixup_self(obj);
217 */
Bram Moolenaar9e70cf12009-05-26 20:59:55 +0000218 return window_size_proc(obj);
219}
Bram Moolenaar75676462013-01-30 14:55:42 +0100220/* with precise GC, w_mzscheme_ref and b_mzscheme_ref are immobile boxes
221 * containing pointers to a window/buffer
222 * with conservative GC these are simply pointers*/
223# define WINDOW_REF(win) *(vim_mz_window **)((win)->w_mzscheme_ref)
224# define BUFFER_REF(buf) *(vim_mz_buffer **)((buf)->b_mzscheme_ref)
225#else
226# define WINDOW_REF(win) (vim_mz_window *)((win)->w_mzscheme_ref)
227# define BUFFER_REF(buf) (vim_mz_buffer *)((buf)->b_mzscheme_ref)
Bram Moolenaar9e70cf12009-05-26 20:59:55 +0000228#endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000229
Bram Moolenaar33570922005-01-25 22:26:29 +0000230#ifdef DYNAMIC_MZSCHEME
Bram Moolenaar33570922005-01-25 22:26:29 +0000231static Scheme_Object *dll_scheme_eof;
232static Scheme_Object *dll_scheme_false;
233static Scheme_Object *dll_scheme_void;
234static Scheme_Object *dll_scheme_null;
235static Scheme_Object *dll_scheme_true;
236
237static Scheme_Thread **dll_scheme_current_thread_ptr;
238
239static void (**dll_scheme_console_printf_ptr)(char *str, ...);
240static void (**dll_scheme_console_output_ptr)(char *str, long len);
241static void (**dll_scheme_notify_multithread_ptr)(int on);
242
243static void *(*dll_GC_malloc)(size_t size_in_bytes);
244static void *(*dll_GC_malloc_atomic)(size_t size_in_bytes);
245static Scheme_Env *(*dll_scheme_basic_env)(void);
246static void (*dll_scheme_check_threads)(void);
247static void (*dll_scheme_register_static)(void *ptr, long size);
248static void (*dll_scheme_set_stack_base)(void *base, int no_auto_statics);
249static void (*dll_scheme_add_global)(const char *name, Scheme_Object *val,
250 Scheme_Env *env);
251static void (*dll_scheme_add_global_symbol)(Scheme_Object *name,
252 Scheme_Object *val, Scheme_Env *env);
253static Scheme_Object *(*dll_scheme_apply)(Scheme_Object *rator, int num_rands,
254 Scheme_Object **rands);
255static Scheme_Object *(*dll_scheme_builtin_value)(const char *name);
Bram Moolenaar555b2802005-05-19 21:08:39 +0000256# if MZSCHEME_VERSION_MAJOR >= 299
257static Scheme_Object *(*dll_scheme_byte_string_to_char_string)(Scheme_Object *s);
258# endif
Bram Moolenaar33570922005-01-25 22:26:29 +0000259static void (*dll_scheme_close_input_port)(Scheme_Object *port);
260static void (*dll_scheme_count_lines)(Scheme_Object *port);
Bram Moolenaar049377e2007-05-12 15:32:12 +0000261#if MZSCHEME_VERSION_MAJOR < 360
Bram Moolenaar33570922005-01-25 22:26:29 +0000262static Scheme_Object *(*dll_scheme_current_continuation_marks)(void);
Bram Moolenaar049377e2007-05-12 15:32:12 +0000263#else
264static Scheme_Object *(*dll_scheme_current_continuation_marks)(Scheme_Object *prompt_tag);
265#endif
Bram Moolenaar33570922005-01-25 22:26:29 +0000266static void (*dll_scheme_display)(Scheme_Object *obj, Scheme_Object *port);
267static char *(*dll_scheme_display_to_string)(Scheme_Object *obj, long *len);
Bram Moolenaar555b2802005-05-19 21:08:39 +0000268static int (*dll_scheme_eq)(Scheme_Object *obj1, Scheme_Object *obj2);
Bram Moolenaar33570922005-01-25 22:26:29 +0000269static Scheme_Object *(*dll_scheme_do_eval)(Scheme_Object *obj,
270 int _num_rands, Scheme_Object **rands, int val);
271static void (*dll_scheme_dont_gc_ptr)(void *p);
272static Scheme_Object *(*dll_scheme_eval)(Scheme_Object *obj, Scheme_Env *env);
273static Scheme_Object *(*dll_scheme_eval_string)(const char *str,
274 Scheme_Env *env);
Bram Moolenaard857f0e2005-06-21 22:37:39 +0000275static Scheme_Object *(*dll_scheme_eval_string_all)(const char *str,
Bram Moolenaar33570922005-01-25 22:26:29 +0000276 Scheme_Env *env, int all);
277static void (*dll_scheme_finish_primitive_module)(Scheme_Env *env);
Bram Moolenaar2e6aff32005-01-31 19:25:36 +0000278# if MZSCHEME_VERSION_MAJOR < 299
Bram Moolenaar33570922005-01-25 22:26:29 +0000279static char *(*dll_scheme_format)(char *format, int flen, int argc,
280 Scheme_Object **argv, long *rlen);
Bram Moolenaar2e6aff32005-01-31 19:25:36 +0000281# else
282static char *(*dll_scheme_format_utf8)(char *format, int flen, int argc,
283 Scheme_Object **argv, long *rlen);
Bram Moolenaar555b2802005-05-19 21:08:39 +0000284static Scheme_Object *(*dll_scheme_get_param)(Scheme_Config *c, int pos);
Bram Moolenaar2e6aff32005-01-31 19:25:36 +0000285# endif
Bram Moolenaar33570922005-01-25 22:26:29 +0000286static void (*dll_scheme_gc_ptr_ok)(void *p);
Bram Moolenaar2e6aff32005-01-31 19:25:36 +0000287# if MZSCHEME_VERSION_MAJOR < 299
Bram Moolenaar33570922005-01-25 22:26:29 +0000288static char *(*dll_scheme_get_sized_string_output)(Scheme_Object *,
289 long *len);
Bram Moolenaar2e6aff32005-01-31 19:25:36 +0000290# else
291static char *(*dll_scheme_get_sized_byte_string_output)(Scheme_Object *,
292 long *len);
293# endif
Bram Moolenaar33570922005-01-25 22:26:29 +0000294static Scheme_Object *(*dll_scheme_intern_symbol)(const char *name);
295static Scheme_Object *(*dll_scheme_lookup_global)(Scheme_Object *symbol,
296 Scheme_Env *env);
297static Scheme_Object *(*dll_scheme_make_closed_prim_w_arity)
298 (Scheme_Closed_Prim *prim, void *data, const char *name, mzshort mina,
299 mzshort maxa);
300static Scheme_Object *(*dll_scheme_make_integer_value)(long i);
Bram Moolenaard857f0e2005-06-21 22:37:39 +0000301static Scheme_Object *(*dll_scheme_make_pair)(Scheme_Object *car,
Bram Moolenaar33570922005-01-25 22:26:29 +0000302 Scheme_Object *cdr);
Bram Moolenaar555b2802005-05-19 21:08:39 +0000303static Scheme_Object *(*dll_scheme_make_prim_w_arity)(Scheme_Prim *prim,
304 const char *name, mzshort mina, mzshort maxa);
Bram Moolenaar2e6aff32005-01-31 19:25:36 +0000305# if MZSCHEME_VERSION_MAJOR < 299
Bram Moolenaar33570922005-01-25 22:26:29 +0000306static Scheme_Object *(*dll_scheme_make_string)(const char *chars);
307static Scheme_Object *(*dll_scheme_make_string_output_port)();
Bram Moolenaar2e6aff32005-01-31 19:25:36 +0000308# else
309static Scheme_Object *(*dll_scheme_make_byte_string)(const char *chars);
310static Scheme_Object *(*dll_scheme_make_byte_string_output_port)();
311# endif
Bram Moolenaar33570922005-01-25 22:26:29 +0000312static Scheme_Object *(*dll_scheme_make_struct_instance)(Scheme_Object *stype,
313 int argc, Scheme_Object **argv);
314static Scheme_Object **(*dll_scheme_make_struct_names)(Scheme_Object *base,
315 Scheme_Object *field_names, int flags, int *count_out);
316static Scheme_Object *(*dll_scheme_make_struct_type)(Scheme_Object *base,
317 Scheme_Object *parent, Scheme_Object *inspector, int num_fields,
318 int num_uninit_fields, Scheme_Object *uninit_val,
Bram Moolenaar2e6aff32005-01-31 19:25:36 +0000319 Scheme_Object *properties
320# if MZSCHEME_VERSION_MAJOR >= 299
321 , Scheme_Object *guard
322# endif
323 );
Bram Moolenaar33570922005-01-25 22:26:29 +0000324static Scheme_Object **(*dll_scheme_make_struct_values)(
325 Scheme_Object *struct_type, Scheme_Object **names, int count,
326 int flags);
327static Scheme_Type (*dll_scheme_make_type)(const char *name);
328static Scheme_Object *(*dll_scheme_make_vector)(int size,
329 Scheme_Object *fill);
330static void *(*dll_scheme_malloc_fail_ok)(void *(*f)(size_t), size_t);
331static Scheme_Object *(*dll_scheme_open_input_file)(const char *name,
332 const char *who);
333static Scheme_Env *(*dll_scheme_primitive_module)(Scheme_Object *name,
334 Scheme_Env *for_env);
335static int (*dll_scheme_proper_list_length)(Scheme_Object *list);
336static void (*dll_scheme_raise)(Scheme_Object *exn);
337static Scheme_Object *(*dll_scheme_read)(Scheme_Object *port);
338static void (*dll_scheme_signal_error)(const char *msg, ...);
339static void (*dll_scheme_wrong_type)(const char *name, const char *expected,
340 int which, int argc, Scheme_Object **argv);
Bram Moolenaar2e6aff32005-01-31 19:25:36 +0000341# if MZSCHEME_VERSION_MAJOR >= 299
Bram Moolenaard857f0e2005-06-21 22:37:39 +0000342static void (*dll_scheme_set_param)(Scheme_Config *c, int pos,
Bram Moolenaar2e6aff32005-01-31 19:25:36 +0000343 Scheme_Object *o);
344static Scheme_Config *(*dll_scheme_current_config)(void);
345static Scheme_Object *(*dll_scheme_char_string_to_byte_string)
346 (Scheme_Object *s);
Bram Moolenaare2a49d82007-07-06 17:43:08 +0000347static Scheme_Object *(*dll_scheme_char_string_to_path)
348 (Scheme_Object *s);
Bram Moolenaar75676462013-01-30 14:55:42 +0100349static void *(*dll_scheme_set_collects_path)(Scheme_Object *p);
Bram Moolenaar2e6aff32005-01-31 19:25:36 +0000350# endif
Bram Moolenaar9e70cf12009-05-26 20:59:55 +0000351static Scheme_Hash_Table *(*dll_scheme_make_hash_table)(int type);
352static void (*dll_scheme_hash_set)(Scheme_Hash_Table *table,
353 Scheme_Object *key, Scheme_Object *value);
354static Scheme_Object *(*dll_scheme_hash_get)(Scheme_Hash_Table *table,
355 Scheme_Object *key);
356static Scheme_Object *(*dll_scheme_make_double)(double d);
357# ifdef INCLUDE_MZSCHEME_BASE
358static Scheme_Object *(*dll_scheme_make_sized_byte_string)(char *chars,
359 long len, int copy);
360static Scheme_Object *(*dll_scheme_namespace_require)(Scheme_Object *req);
361# endif
Bram Moolenaar33570922005-01-25 22:26:29 +0000362
363/* arrays are imported directly */
364# define scheme_eof dll_scheme_eof
365# define scheme_false dll_scheme_false
366# define scheme_void dll_scheme_void
367# define scheme_null dll_scheme_null
368# define scheme_true dll_scheme_true
369
370/* pointers are GetProceAddress'ed as pointers to pointer */
371# define scheme_current_thread (*dll_scheme_current_thread_ptr)
372# define scheme_console_printf (*dll_scheme_console_printf_ptr)
373# define scheme_console_output (*dll_scheme_console_output_ptr)
374# define scheme_notify_multithread (*dll_scheme_notify_multithread_ptr)
375
376/* and functions in a usual way */
377# define GC_malloc dll_GC_malloc
378# define GC_malloc_atomic dll_GC_malloc_atomic
379
380# define scheme_add_global dll_scheme_add_global
381# define scheme_add_global_symbol dll_scheme_add_global_symbol
382# define scheme_apply dll_scheme_apply
383# define scheme_basic_env dll_scheme_basic_env
384# define scheme_builtin_value dll_scheme_builtin_value
Bram Moolenaar555b2802005-05-19 21:08:39 +0000385# if MZSCHEME_VERSION_MAJOR >= 299
386# define scheme_byte_string_to_char_string dll_scheme_byte_string_to_char_string
387# endif
Bram Moolenaar33570922005-01-25 22:26:29 +0000388# define scheme_check_threads dll_scheme_check_threads
389# define scheme_close_input_port dll_scheme_close_input_port
390# define scheme_count_lines dll_scheme_count_lines
391# define scheme_current_continuation_marks \
392 dll_scheme_current_continuation_marks
393# define scheme_display dll_scheme_display
394# define scheme_display_to_string dll_scheme_display_to_string
395# define scheme_do_eval dll_scheme_do_eval
396# define scheme_dont_gc_ptr dll_scheme_dont_gc_ptr
Bram Moolenaar555b2802005-05-19 21:08:39 +0000397# define scheme_eq dll_scheme_eq
Bram Moolenaar33570922005-01-25 22:26:29 +0000398# define scheme_eval dll_scheme_eval
399# define scheme_eval_string dll_scheme_eval_string
400# define scheme_eval_string_all dll_scheme_eval_string_all
401# define scheme_finish_primitive_module dll_scheme_finish_primitive_module
Bram Moolenaar2e6aff32005-01-31 19:25:36 +0000402# if MZSCHEME_VERSION_MAJOR < 299
403# define scheme_format dll_scheme_format
404# else
405# define scheme_format_utf8 dll_scheme_format_utf8
406# endif
Bram Moolenaar33570922005-01-25 22:26:29 +0000407# define scheme_gc_ptr_ok dll_scheme_gc_ptr_ok
Bram Moolenaar2e6aff32005-01-31 19:25:36 +0000408# if MZSCHEME_VERSION_MAJOR < 299
Bram Moolenaar75676462013-01-30 14:55:42 +0100409# define scheme_get_sized_byte_string_output dll_scheme_get_sized_string_output
Bram Moolenaar2e6aff32005-01-31 19:25:36 +0000410# else
411# define scheme_get_sized_byte_string_output \
412 dll_scheme_get_sized_byte_string_output
Bram Moolenaar75676462013-01-30 14:55:42 +0100413# define scheme_get_param dll_scheme_get_param
Bram Moolenaar2e6aff32005-01-31 19:25:36 +0000414# endif
Bram Moolenaar33570922005-01-25 22:26:29 +0000415# define scheme_intern_symbol dll_scheme_intern_symbol
416# define scheme_lookup_global dll_scheme_lookup_global
417# define scheme_make_closed_prim_w_arity dll_scheme_make_closed_prim_w_arity
418# define scheme_make_integer_value dll_scheme_make_integer_value
Bram Moolenaar33570922005-01-25 22:26:29 +0000419# define scheme_make_pair dll_scheme_make_pair
Bram Moolenaar555b2802005-05-19 21:08:39 +0000420# define scheme_make_prim_w_arity dll_scheme_make_prim_w_arity
Bram Moolenaar2e6aff32005-01-31 19:25:36 +0000421# if MZSCHEME_VERSION_MAJOR < 299
Bram Moolenaar75676462013-01-30 14:55:42 +0100422# define scheme_make_byte_string dll_scheme_make_string
423# define scheme_make_byte_string_output_port dll_scheme_make_string_output_port
Bram Moolenaar2e6aff32005-01-31 19:25:36 +0000424# else
425# define scheme_make_byte_string dll_scheme_make_byte_string
426# define scheme_make_byte_string_output_port \
427 dll_scheme_make_byte_string_output_port
428# endif
Bram Moolenaar33570922005-01-25 22:26:29 +0000429# define scheme_make_struct_instance dll_scheme_make_struct_instance
430# define scheme_make_struct_names dll_scheme_make_struct_names
431# define scheme_make_struct_type dll_scheme_make_struct_type
432# define scheme_make_struct_values dll_scheme_make_struct_values
433# define scheme_make_type dll_scheme_make_type
434# define scheme_make_vector dll_scheme_make_vector
435# define scheme_malloc_fail_ok dll_scheme_malloc_fail_ok
436# define scheme_open_input_file dll_scheme_open_input_file
437# define scheme_primitive_module dll_scheme_primitive_module
438# define scheme_proper_list_length dll_scheme_proper_list_length
439# define scheme_raise dll_scheme_raise
440# define scheme_read dll_scheme_read
441# define scheme_register_static dll_scheme_register_static
442# define scheme_set_stack_base dll_scheme_set_stack_base
443# define scheme_signal_error dll_scheme_signal_error
444# define scheme_wrong_type dll_scheme_wrong_type
Bram Moolenaar2e6aff32005-01-31 19:25:36 +0000445# if MZSCHEME_VERSION_MAJOR >= 299
446# define scheme_set_param dll_scheme_set_param
447# define scheme_current_config dll_scheme_current_config
448# define scheme_char_string_to_byte_string \
449 dll_scheme_char_string_to_byte_string
Bram Moolenaare2a49d82007-07-06 17:43:08 +0000450# define scheme_char_string_to_path \
451 dll_scheme_char_string_to_path
Bram Moolenaar75676462013-01-30 14:55:42 +0100452# define scheme_set_collects_path dll_scheme_set_collects_path
Bram Moolenaar2e6aff32005-01-31 19:25:36 +0000453# endif
Bram Moolenaar9e70cf12009-05-26 20:59:55 +0000454# define scheme_make_hash_table dll_scheme_make_hash_table
455# define scheme_hash_set dll_scheme_hash_set
456# define scheme_hash_get dll_scheme_hash_get
457# define scheme_make_double dll_scheme_make_double
458# ifdef INCLUDE_MZSCHEME_BASE
459# define scheme_make_sized_byte_string dll_scheme_make_sized_byte_string
460# define scheme_namespace_require dll_scheme_namespace_require
461# endif
Bram Moolenaar33570922005-01-25 22:26:29 +0000462
463typedef struct
464{
465 char *name;
466 void **ptr;
467} Thunk_Info;
468
469static Thunk_Info mzgc_imports[] = {
470 {"GC_malloc", (void **)&dll_GC_malloc},
471 {"GC_malloc_atomic", (void **)&dll_GC_malloc_atomic},
472 {NULL, NULL}};
473
474static Thunk_Info mzsch_imports[] = {
475 {"scheme_eof", (void **)&dll_scheme_eof},
476 {"scheme_false", (void **)&dll_scheme_false},
477 {"scheme_void", (void **)&dll_scheme_void},
478 {"scheme_null", (void **)&dll_scheme_null},
479 {"scheme_true", (void **)&dll_scheme_true},
480 {"scheme_current_thread", (void **)&dll_scheme_current_thread_ptr},
481 {"scheme_console_printf", (void **)&dll_scheme_console_printf_ptr},
482 {"scheme_console_output", (void **)&dll_scheme_console_output_ptr},
Bram Moolenaard857f0e2005-06-21 22:37:39 +0000483 {"scheme_notify_multithread",
Bram Moolenaar33570922005-01-25 22:26:29 +0000484 (void **)&dll_scheme_notify_multithread_ptr},
485 {"scheme_add_global", (void **)&dll_scheme_add_global},
486 {"scheme_add_global_symbol", (void **)&dll_scheme_add_global_symbol},
487 {"scheme_apply", (void **)&dll_scheme_apply},
488 {"scheme_basic_env", (void **)&dll_scheme_basic_env},
Bram Moolenaar555b2802005-05-19 21:08:39 +0000489# if MZSCHEME_VERSION_MAJOR >= 299
490 {"scheme_byte_string_to_char_string", (void **)&dll_scheme_byte_string_to_char_string},
491# endif
Bram Moolenaar33570922005-01-25 22:26:29 +0000492 {"scheme_builtin_value", (void **)&dll_scheme_builtin_value},
493 {"scheme_check_threads", (void **)&dll_scheme_check_threads},
494 {"scheme_close_input_port", (void **)&dll_scheme_close_input_port},
495 {"scheme_count_lines", (void **)&dll_scheme_count_lines},
Bram Moolenaard857f0e2005-06-21 22:37:39 +0000496 {"scheme_current_continuation_marks",
Bram Moolenaar33570922005-01-25 22:26:29 +0000497 (void **)&dll_scheme_current_continuation_marks},
498 {"scheme_display", (void **)&dll_scheme_display},
499 {"scheme_display_to_string", (void **)&dll_scheme_display_to_string},
500 {"scheme_do_eval", (void **)&dll_scheme_do_eval},
501 {"scheme_dont_gc_ptr", (void **)&dll_scheme_dont_gc_ptr},
Bram Moolenaar555b2802005-05-19 21:08:39 +0000502 {"scheme_eq", (void **)&dll_scheme_eq},
Bram Moolenaar33570922005-01-25 22:26:29 +0000503 {"scheme_eval", (void **)&dll_scheme_eval},
504 {"scheme_eval_string", (void **)&dll_scheme_eval_string},
505 {"scheme_eval_string_all", (void **)&dll_scheme_eval_string_all},
Bram Moolenaard857f0e2005-06-21 22:37:39 +0000506 {"scheme_finish_primitive_module",
Bram Moolenaar33570922005-01-25 22:26:29 +0000507 (void **)&dll_scheme_finish_primitive_module},
Bram Moolenaar2e6aff32005-01-31 19:25:36 +0000508# if MZSCHEME_VERSION_MAJOR < 299
Bram Moolenaar33570922005-01-25 22:26:29 +0000509 {"scheme_format", (void **)&dll_scheme_format},
Bram Moolenaar2e6aff32005-01-31 19:25:36 +0000510# else
511 {"scheme_format_utf8", (void **)&dll_scheme_format_utf8},
Bram Moolenaar555b2802005-05-19 21:08:39 +0000512 {"scheme_get_param", (void **)&dll_scheme_get_param},
Bram Moolenaar2e6aff32005-01-31 19:25:36 +0000513#endif
Bram Moolenaar33570922005-01-25 22:26:29 +0000514 {"scheme_gc_ptr_ok", (void **)&dll_scheme_gc_ptr_ok},
Bram Moolenaar2e6aff32005-01-31 19:25:36 +0000515# if MZSCHEME_VERSION_MAJOR < 299
Bram Moolenaard857f0e2005-06-21 22:37:39 +0000516 {"scheme_get_sized_string_output",
Bram Moolenaar33570922005-01-25 22:26:29 +0000517 (void **)&dll_scheme_get_sized_string_output},
Bram Moolenaar2e6aff32005-01-31 19:25:36 +0000518# else
Bram Moolenaard857f0e2005-06-21 22:37:39 +0000519 {"scheme_get_sized_byte_string_output",
Bram Moolenaar2e6aff32005-01-31 19:25:36 +0000520 (void **)&dll_scheme_get_sized_byte_string_output},
521#endif
Bram Moolenaar33570922005-01-25 22:26:29 +0000522 {"scheme_intern_symbol", (void **)&dll_scheme_intern_symbol},
523 {"scheme_lookup_global", (void **)&dll_scheme_lookup_global},
Bram Moolenaard857f0e2005-06-21 22:37:39 +0000524 {"scheme_make_closed_prim_w_arity",
Bram Moolenaar33570922005-01-25 22:26:29 +0000525 (void **)&dll_scheme_make_closed_prim_w_arity},
526 {"scheme_make_integer_value", (void **)&dll_scheme_make_integer_value},
Bram Moolenaar33570922005-01-25 22:26:29 +0000527 {"scheme_make_pair", (void **)&dll_scheme_make_pair},
Bram Moolenaar555b2802005-05-19 21:08:39 +0000528 {"scheme_make_prim_w_arity", (void **)&dll_scheme_make_prim_w_arity},
Bram Moolenaar2e6aff32005-01-31 19:25:36 +0000529# if MZSCHEME_VERSION_MAJOR < 299
Bram Moolenaar33570922005-01-25 22:26:29 +0000530 {"scheme_make_string", (void **)&dll_scheme_make_string},
Bram Moolenaard857f0e2005-06-21 22:37:39 +0000531 {"scheme_make_string_output_port",
Bram Moolenaar33570922005-01-25 22:26:29 +0000532 (void **)&dll_scheme_make_string_output_port},
Bram Moolenaar2e6aff32005-01-31 19:25:36 +0000533# else
534 {"scheme_make_byte_string", (void **)&dll_scheme_make_byte_string},
Bram Moolenaard857f0e2005-06-21 22:37:39 +0000535 {"scheme_make_byte_string_output_port",
Bram Moolenaar2e6aff32005-01-31 19:25:36 +0000536 (void **)&dll_scheme_make_byte_string_output_port},
537# endif
Bram Moolenaard857f0e2005-06-21 22:37:39 +0000538 {"scheme_make_struct_instance",
Bram Moolenaar33570922005-01-25 22:26:29 +0000539 (void **)&dll_scheme_make_struct_instance},
540 {"scheme_make_struct_names", (void **)&dll_scheme_make_struct_names},
541 {"scheme_make_struct_type", (void **)&dll_scheme_make_struct_type},
542 {"scheme_make_struct_values", (void **)&dll_scheme_make_struct_values},
543 {"scheme_make_type", (void **)&dll_scheme_make_type},
544 {"scheme_make_vector", (void **)&dll_scheme_make_vector},
545 {"scheme_malloc_fail_ok", (void **)&dll_scheme_malloc_fail_ok},
546 {"scheme_open_input_file", (void **)&dll_scheme_open_input_file},
547 {"scheme_primitive_module", (void **)&dll_scheme_primitive_module},
548 {"scheme_proper_list_length", (void **)&dll_scheme_proper_list_length},
549 {"scheme_raise", (void **)&dll_scheme_raise},
550 {"scheme_read", (void **)&dll_scheme_read},
551 {"scheme_register_static", (void **)&dll_scheme_register_static},
552 {"scheme_set_stack_base", (void **)&dll_scheme_set_stack_base},
553 {"scheme_signal_error", (void **)&dll_scheme_signal_error},
554 {"scheme_wrong_type", (void **)&dll_scheme_wrong_type},
Bram Moolenaar2e6aff32005-01-31 19:25:36 +0000555# if MZSCHEME_VERSION_MAJOR >= 299
556 {"scheme_set_param", (void **)&dll_scheme_set_param},
557 {"scheme_current_config", (void **)&dll_scheme_current_config},
558 {"scheme_char_string_to_byte_string",
559 (void **)&dll_scheme_char_string_to_byte_string},
Bram Moolenaar9e70cf12009-05-26 20:59:55 +0000560 {"scheme_char_string_to_path", (void **)&dll_scheme_char_string_to_path},
Bram Moolenaar75676462013-01-30 14:55:42 +0100561 {"scheme_set_collects_path", (void **)&dll_scheme_set_collects_path},
Bram Moolenaar2e6aff32005-01-31 19:25:36 +0000562# endif
Bram Moolenaar9e70cf12009-05-26 20:59:55 +0000563 {"scheme_make_hash_table", (void **)&dll_scheme_make_hash_table},
564 {"scheme_hash_set", (void **)&dll_scheme_hash_set},
565 {"scheme_hash_get", (void **)&dll_scheme_hash_get},
566 {"scheme_make_double", (void **)&dll_scheme_make_double},
567# ifdef INCLUDE_MZSCHEME_BASE
568 {"scheme_make_sized_byte_string", (void **)&dll_scheme_make_sized_byte_string},
569 {"scheme_namespace_require", (void **)&dll_scheme_namespace_require},
570#endif
Bram Moolenaar33570922005-01-25 22:26:29 +0000571 {NULL, NULL}};
572
573static HINSTANCE hMzGC = 0;
574static HINSTANCE hMzSch = 0;
575
576static void dynamic_mzscheme_end(void);
577static int mzscheme_runtime_link_init(char *sch_dll, char *gc_dll,
578 int verbose);
579
580 static int
581mzscheme_runtime_link_init(char *sch_dll, char *gc_dll, int verbose)
582{
583 Thunk_Info *thunk = NULL;
584
585 if (hMzGC && hMzSch)
586 return OK;
Bram Moolenaarebbcb822010-10-23 14:02:54 +0200587 hMzSch = vimLoadLib(sch_dll);
588 hMzGC = vimLoadLib(gc_dll);
Bram Moolenaar33570922005-01-25 22:26:29 +0000589
Bram Moolenaar33570922005-01-25 22:26:29 +0000590 if (!hMzGC)
591 {
592 if (verbose)
593 EMSG2(_(e_loadlib), gc_dll);
594 return FAIL;
595 }
596
Bram Moolenaarbbc98db2012-02-12 01:55:55 +0100597 if (!hMzSch)
598 {
599 if (verbose)
600 EMSG2(_(e_loadlib), sch_dll);
601 return FAIL;
602 }
603
Bram Moolenaar33570922005-01-25 22:26:29 +0000604 for (thunk = mzsch_imports; thunk->name; thunk++)
605 {
Bram Moolenaard857f0e2005-06-21 22:37:39 +0000606 if ((*thunk->ptr =
Bram Moolenaar33570922005-01-25 22:26:29 +0000607 (void *)GetProcAddress(hMzSch, thunk->name)) == NULL)
608 {
609 FreeLibrary(hMzSch);
610 hMzSch = 0;
611 FreeLibrary(hMzGC);
612 hMzGC = 0;
613 if (verbose)
614 EMSG2(_(e_loadfunc), thunk->name);
615 return FAIL;
616 }
617 }
618 for (thunk = mzgc_imports; thunk->name; thunk++)
619 {
Bram Moolenaard857f0e2005-06-21 22:37:39 +0000620 if ((*thunk->ptr =
Bram Moolenaar33570922005-01-25 22:26:29 +0000621 (void *)GetProcAddress(hMzGC, thunk->name)) == NULL)
622 {
623 FreeLibrary(hMzSch);
624 hMzSch = 0;
625 FreeLibrary(hMzGC);
626 hMzGC = 0;
627 if (verbose)
628 EMSG2(_(e_loadfunc), thunk->name);
629 return FAIL;
630 }
631 }
632 return OK;
633}
634
635 int
636mzscheme_enabled(int verbose)
637{
638 return mzscheme_runtime_link_init(
639 DYNAMIC_MZSCH_DLL, DYNAMIC_MZGC_DLL, verbose) == OK;
640}
641
642 static void
643dynamic_mzscheme_end(void)
644{
645 if (hMzSch)
646 {
647 FreeLibrary(hMzSch);
648 hMzSch = 0;
649 }
650 if (hMzGC)
651 {
652 FreeLibrary(hMzGC);
653 hMzGC = 0;
654 }
655}
656#endif /* DYNAMIC_MZSCHEME */
657
Bram Moolenaar75676462013-01-30 14:55:42 +0100658#if MZSCHEME_VERSION_MAJOR < 299
659# define GUARANTEED_STRING_ARG(proc, num) GUARANTEE_STRING(proc, num)
660#else
661 static Scheme_Object *
662guaranteed_byte_string_arg(char *proc, int num, int argc, Scheme_Object **argv)
663{
664 if (SCHEME_BYTE_STRINGP(argv[num]))
665 {
666 return argv[num];
667 }
668 else if (SCHEME_CHAR_STRINGP(argv[num]))
669 {
670 Scheme_Object *tmp = NULL;
671 MZ_GC_DECL_REG(2);
672 MZ_GC_VAR_IN_REG(0, argv[num]);
673 MZ_GC_VAR_IN_REG(1, tmp);
674 MZ_GC_REG();
675 tmp = scheme_char_string_to_byte_string(argv[num]);
676 MZ_GC_UNREG();
677 return tmp;
678 }
679 else
680 scheme_wrong_type(proc, "string", num, argc, argv);
681 /* unreachable */
682 return scheme_void;
683}
684# define GUARANTEED_STRING_ARG(proc, num) guaranteed_byte_string_arg(proc, num, argc, argv)
685#endif
686
Bram Moolenaar9e70cf12009-05-26 20:59:55 +0000687/* need to put it here for dynamic stuff to work */
Bram Moolenaare484c942009-09-11 10:21:41 +0000688#if defined(INCLUDE_MZSCHEME_BASE)
Bram Moolenaar9e70cf12009-05-26 20:59:55 +0000689# include "mzscheme_base.c"
Bram Moolenaare484c942009-09-11 10:21:41 +0000690#elif MZSCHEME_VERSION_MAJOR >= 400
Bram Moolenaar75676462013-01-30 14:55:42 +0100691# error MzScheme >=4 must include mzscheme_base.c, for MinGW32 you need to define MZSCHEME_GENERATE_BASE=yes
Bram Moolenaar9e70cf12009-05-26 20:59:55 +0000692#endif
693
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000694/*
695 *========================================================================
696 * 1. MzScheme interpreter startup
697 *========================================================================
698 */
699
700static Scheme_Type mz_buffer_type;
701static Scheme_Type mz_window_type;
702
Bram Moolenaar9e70cf12009-05-26 20:59:55 +0000703static int initialized = FALSE;
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000704
705/* global environment */
706static Scheme_Env *environment = NULL;
707/* output/error handlers */
708static Scheme_Object *curout = NULL;
709static Scheme_Object *curerr = NULL;
Bram Moolenaar9e70cf12009-05-26 20:59:55 +0000710/* exn:vim exception */
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000711static Scheme_Object *exn_catching_apply = NULL;
712static Scheme_Object *exn_p = NULL;
713static Scheme_Object *exn_message = NULL;
714static Scheme_Object *vim_exn = NULL; /* Vim Error exception */
Bram Moolenaar9e70cf12009-05-26 20:59:55 +0000715
716#if !defined(MZ_PRECISE_GC) || MZSCHEME_VERSION_MAJOR < 400
717static void *stack_base = NULL;
718#endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000719
720static long range_start;
721static long range_end;
722
723/* MzScheme threads scheduling stuff */
724static int mz_threads_allow = 0;
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000725
726#if defined(FEAT_GUI_W32)
727static void CALLBACK timer_proc(HWND, UINT, UINT, DWORD);
728static UINT timer_id = 0;
729#elif defined(FEAT_GUI_GTK)
730static gint timer_proc(gpointer);
731static guint timer_id = 0;
732#elif defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_ATHENA)
733static void timer_proc(XtPointer, XtIntervalId *);
734static XtIntervalId timer_id = (XtIntervalId)0;
735#elif defined(FEAT_GUI_MAC)
736pascal void timer_proc(EventLoopTimerRef, void *);
737static EventLoopTimerRef timer_id = NULL;
738static EventLoopTimerUPP timerUPP;
739#endif
740
741#ifndef FEAT_GUI_W32 /* Win32 console and Unix */
742 void
743mzvim_check_threads(void)
744{
745 /* Last time MzScheme threads were scheduled */
746 static time_t mz_last_time = 0;
747
748 if (mz_threads_allow && p_mzq > 0)
749 {
750 time_t now = time(NULL);
751
752 if ((now - mz_last_time) * 1000 > p_mzq)
753 {
754 mz_last_time = now;
755 scheme_check_threads();
756 }
757 }
758}
759#endif
760
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +0000761#ifdef MZSCHEME_GUI_THREADS
762static void setup_timer(void);
763static void remove_timer(void);
764
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000765/* timers are presented in GUI only */
766# if defined(FEAT_GUI_W32)
767 static void CALLBACK
Bram Moolenaar64404472010-06-26 06:24:45 +0200768timer_proc(HWND hwnd UNUSED, UINT uMsg UNUSED, UINT idEvent UNUSED, DWORD dwTime UNUSED)
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000769# elif defined(FEAT_GUI_GTK)
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000770 static gint
Bram Moolenaar64404472010-06-26 06:24:45 +0200771timer_proc(gpointer data UNUSED)
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000772# elif defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_ATHENA)
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000773 static void
Bram Moolenaar64404472010-06-26 06:24:45 +0200774timer_proc(XtPointer timed_out UNUSED, XtIntervalId *interval_id UNUSED)
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000775# elif defined(FEAT_GUI_MAC)
776 pascal void
Bram Moolenaar64404472010-06-26 06:24:45 +0200777timer_proc(EventLoopTimerRef theTimer UNUSED, void *userData UNUSED)
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000778# endif
779{
780 scheme_check_threads();
781# if defined(FEAT_GUI_GTK)
782 return TRUE; /* continue receiving notifications */
783# elif defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_ATHENA)
784 /* renew timeout */
785 if (mz_threads_allow && p_mzq > 0)
786 timer_id = XtAppAddTimeOut(app_context, p_mzq,
787 timer_proc, NULL);
788# endif
789}
790
791 static void
792setup_timer(void)
793{
794# if defined(FEAT_GUI_W32)
795 timer_id = SetTimer(NULL, 0, p_mzq, timer_proc);
796# elif defined(FEAT_GUI_GTK)
797 timer_id = gtk_timeout_add((guint32)p_mzq, (GtkFunction)timer_proc, NULL);
798# elif defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_ATHENA)
799 timer_id = XtAppAddTimeOut(app_context, p_mzq, timer_proc, NULL);
800# elif defined(FEAT_GUI_MAC)
801 timerUPP = NewEventLoopTimerUPP(timer_proc);
802 InstallEventLoopTimer(GetMainEventLoop(), p_mzq * kEventDurationMillisecond,
803 p_mzq * kEventDurationMillisecond, timerUPP, NULL, &timer_id);
804# endif
805}
806
807 static void
808remove_timer(void)
809{
810# if defined(FEAT_GUI_W32)
811 KillTimer(NULL, timer_id);
812# elif defined(FEAT_GUI_GTK)
813 gtk_timeout_remove(timer_id);
814# elif defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_ATHENA)
815 XtRemoveTimeOut(timer_id);
816# elif defined(FEAT_GUI_MAC)
817 RemoveEventLoopTimer(timer_id);
818 DisposeEventLoopTimerUPP(timerUPP);
819# endif
820 timer_id = 0;
821}
822
823 void
824mzvim_reset_timer(void)
825{
826 if (timer_id != 0)
827 remove_timer();
828 if (mz_threads_allow && p_mzq > 0 && gui.in_use)
829 setup_timer();
830}
831
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +0000832#endif /* MZSCHEME_GUI_THREADS */
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000833
834 static void
835notify_multithread(int on)
836{
837 mz_threads_allow = on;
Bram Moolenaar2df6dcc2004-07-12 15:53:54 +0000838#ifdef MZSCHEME_GUI_THREADS
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000839 if (on && timer_id == 0 && p_mzq > 0 && gui.in_use)
840 setup_timer();
841 if (!on && timer_id != 0)
842 remove_timer();
843#endif
844}
845
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000846 void
847mzscheme_end(void)
848{
Bram Moolenaar33570922005-01-25 22:26:29 +0000849#ifdef DYNAMIC_MZSCHEME
850 dynamic_mzscheme_end();
851#endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000852}
853
Bram Moolenaar2d0860d2010-11-03 21:59:30 +0100854#if MZSCHEME_VERSION_MAJOR >= 500 && defined(WIN32) && defined(USE_THREAD_LOCAL)
855static __declspec(thread) void *tls_space;
856#endif
857
Bram Moolenaarbbc98db2012-02-12 01:55:55 +0100858/*
859 * Since version 4.x precise GC requires trampolined startup.
860 * Futures and places in version 5.x need it too.
861 */
862#if defined(MZ_PRECISE_GC) && MZSCHEME_VERSION_MAJOR >= 400 \
863 || MZSCHEME_VERSION_MAJOR >= 500 && (defined(MZ_USE_FUTURES) || defined(MZ_USE_PLACES))
864# ifdef DYNAMIC_MZSCHEME
865# error Precise GC v.4+ or Racket with futures/places do not support dynamic MzScheme
866# endif
867# define TRAMPOLINED_MZVIM_STARTUP
868#endif
869
870 int
871mzscheme_main(int argc, char** argv)
Bram Moolenaar9e70cf12009-05-26 20:59:55 +0000872{
Bram Moolenaar2d0860d2010-11-03 21:59:30 +0100873#if MZSCHEME_VERSION_MAJOR >= 500 && defined(WIN32) && defined(USE_THREAD_LOCAL)
874 scheme_register_tls_space(&tls_space, 0);
875#endif
Bram Moolenaarbbc98db2012-02-12 01:55:55 +0100876#ifdef TRAMPOLINED_MZVIM_STARTUP
877 return scheme_main_setup(TRUE, mzscheme_env_main, argc, argv);
Bram Moolenaar9e70cf12009-05-26 20:59:55 +0000878#else
Bram Moolenaarbbc98db2012-02-12 01:55:55 +0100879 return mzscheme_env_main(NULL, argc, argv);
Bram Moolenaar9e70cf12009-05-26 20:59:55 +0000880#endif
881}
882
883 static int
Bram Moolenaarbbc98db2012-02-12 01:55:55 +0100884mzscheme_env_main(Scheme_Env *env, int argc, char **argv)
Bram Moolenaar9e70cf12009-05-26 20:59:55 +0000885{
Bram Moolenaarbbc98db2012-02-12 01:55:55 +0100886 int vim_main_result;
887#ifdef TRAMPOLINED_MZVIM_STARTUP
888 /* Scheme has created the environment for us */
889 environment = env;
890#else
891# ifdef MZ_PRECISE_GC
Bram Moolenaar9e70cf12009-05-26 20:59:55 +0000892 Scheme_Object *dummy = NULL;
893 MZ_GC_DECL_REG(1);
894 MZ_GC_VAR_IN_REG(0, dummy);
895
896 stack_base = &__gc_var_stack__;
897# else
Bram Moolenaar9e70cf12009-05-26 20:59:55 +0000898 int dummy = 0;
899 stack_base = (void *)&dummy;
Bram Moolenaarbbc98db2012-02-12 01:55:55 +0100900# endif
Bram Moolenaar9e70cf12009-05-26 20:59:55 +0000901#endif
Bram Moolenaarbbc98db2012-02-12 01:55:55 +0100902
903 /* mzscheme_main is called as a trampoline from main.
904 * We trampoline into vim_main2
905 * Passing argc, argv through from mzscheme_main
906 */
907 vim_main_result = vim_main2(argc, argv);
908#if !defined(TRAMPOLINED_MZVIM_STARTUP) && defined(MZ_PRECISE_GC)
Bram Moolenaar9e70cf12009-05-26 20:59:55 +0000909 /* releasing dummy */
910 MZ_GC_REG();
911 MZ_GC_UNREG();
912#endif
Bram Moolenaarbbc98db2012-02-12 01:55:55 +0100913 return vim_main_result;
Bram Moolenaar9e70cf12009-05-26 20:59:55 +0000914}
915
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000916 static void
917startup_mzscheme(void)
918{
Bram Moolenaarbbc98db2012-02-12 01:55:55 +0100919#ifndef TRAMPOLINED_MZVIM_STARTUP
Bram Moolenaar9e70cf12009-05-26 20:59:55 +0000920 scheme_set_stack_base(stack_base, 1);
921#endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000922
Bram Moolenaar75676462013-01-30 14:55:42 +0100923#ifndef TRAMPOLINED_MZVIM_STARTUP
924 /* in newer versions of precise GC the initial env has been created */
925 environment = scheme_basic_env();
926#endif
927
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000928 MZ_REGISTER_STATIC(environment);
929 MZ_REGISTER_STATIC(curout);
930 MZ_REGISTER_STATIC(curerr);
931 MZ_REGISTER_STATIC(exn_catching_apply);
932 MZ_REGISTER_STATIC(exn_p);
933 MZ_REGISTER_STATIC(exn_message);
934 MZ_REGISTER_STATIC(vim_exn);
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000935
Bram Moolenaar9e70cf12009-05-26 20:59:55 +0000936 MZ_GC_CHECK();
937
938#ifdef INCLUDE_MZSCHEME_BASE
939 {
940 /*
Bram Moolenaare484c942009-09-11 10:21:41 +0000941 * versions 4.x do not provide Scheme bindings by default
Bram Moolenaar9e70cf12009-05-26 20:59:55 +0000942 * we need to add them explicitly
943 */
944 Scheme_Object *scheme_base_symbol = NULL;
945 MZ_GC_DECL_REG(1);
946 MZ_GC_VAR_IN_REG(0, scheme_base_symbol);
947 MZ_GC_REG();
Bram Moolenaare484c942009-09-11 10:21:41 +0000948 /* invoke function from generated and included mzscheme_base.c */
Bram Moolenaar9e70cf12009-05-26 20:59:55 +0000949 declare_modules(environment);
950 scheme_base_symbol = scheme_intern_symbol("scheme/base");
951 MZ_GC_CHECK();
952 scheme_namespace_require(scheme_base_symbol);
953 MZ_GC_CHECK();
954 MZ_GC_UNREG();
955 }
956#endif
957 register_vim_exn();
958 /* use new environment to initialise exception handling */
959 init_exn_catching_apply();
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000960
961 /* redirect output */
962 scheme_console_output = do_output;
963 scheme_console_printf = do_printf;
964
965#ifdef MZSCHEME_COLLECTS
966 /* setup 'current-library-collection-paths' parameter */
Bram Moolenaare2a49d82007-07-06 17:43:08 +0000967# if MZSCHEME_VERSION_MAJOR >= 299
Bram Moolenaar39d7d512013-01-31 21:09:15 +0100968# ifdef MACOS
Bram Moolenaar9e70cf12009-05-26 20:59:55 +0000969 {
970 Scheme_Object *coll_byte_string = NULL;
971 Scheme_Object *coll_char_string = NULL;
972 Scheme_Object *coll_path = NULL;
Bram Moolenaar9e70cf12009-05-26 20:59:55 +0000973
Bram Moolenaar75676462013-01-30 14:55:42 +0100974 MZ_GC_DECL_REG(3);
Bram Moolenaar9e70cf12009-05-26 20:59:55 +0000975 MZ_GC_VAR_IN_REG(0, coll_byte_string);
976 MZ_GC_VAR_IN_REG(1, coll_char_string);
977 MZ_GC_VAR_IN_REG(2, coll_path);
Bram Moolenaar9e70cf12009-05-26 20:59:55 +0000978 MZ_GC_REG();
979 coll_byte_string = scheme_make_byte_string(MZSCHEME_COLLECTS);
980 MZ_GC_CHECK();
981 coll_char_string = scheme_byte_string_to_char_string(coll_byte_string);
982 MZ_GC_CHECK();
983 coll_path = scheme_char_string_to_path(coll_char_string);
984 MZ_GC_CHECK();
Bram Moolenaar75676462013-01-30 14:55:42 +0100985 scheme_set_collects_path(coll_path);
Bram Moolenaar9e70cf12009-05-26 20:59:55 +0000986 MZ_GC_CHECK();
987 MZ_GC_UNREG();
988 }
Bram Moolenaar39d7d512013-01-31 21:09:15 +0100989# else
990 {
991 Scheme_Object *coll_byte_string = NULL;
992 Scheme_Object *coll_char_string = NULL;
993 Scheme_Object *coll_path = NULL;
994 Scheme_Object *coll_pair = NULL;
995 Scheme_Config *config = NULL;
996
997 MZ_GC_DECL_REG(5);
998 MZ_GC_VAR_IN_REG(0, coll_byte_string);
999 MZ_GC_VAR_IN_REG(1, coll_char_string);
1000 MZ_GC_VAR_IN_REG(2, coll_path);
1001 MZ_GC_VAR_IN_REG(3, coll_pair);
1002 MZ_GC_VAR_IN_REG(4, config);
1003 MZ_GC_REG();
1004 coll_byte_string = scheme_make_byte_string(MZSCHEME_COLLECTS);
1005 MZ_GC_CHECK();
1006 coll_char_string = scheme_byte_string_to_char_string(coll_byte_string);
1007 MZ_GC_CHECK();
1008 coll_path = scheme_char_string_to_path(coll_char_string);
1009 MZ_GC_CHECK();
1010 coll_pair = scheme_make_pair(coll_path, scheme_null);
1011 MZ_GC_CHECK();
1012 config = scheme_current_config();
1013 MZ_GC_CHECK();
1014 scheme_set_param(config, MZCONFIG_COLLECTION_PATHS, coll_pair);
1015 MZ_GC_CHECK();
1016 MZ_GC_UNREG();
1017 }
1018# endif
Bram Moolenaare2a49d82007-07-06 17:43:08 +00001019# else
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00001020 {
1021 Scheme_Object *coll_string = NULL;
1022 Scheme_Object *coll_pair = NULL;
1023 Scheme_Config *config = NULL;
1024
1025 MZ_GC_DECL_REG(3);
1026 MZ_GC_VAR_IN_REG(0, coll_string);
1027 MZ_GC_VAR_IN_REG(1, coll_pair);
1028 MZ_GC_VAR_IN_REG(2, config);
1029 MZ_GC_REG();
Bram Moolenaar75676462013-01-30 14:55:42 +01001030 coll_string = scheme_make_byte_string(MZSCHEME_COLLECTS);
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00001031 MZ_GC_CHECK();
1032 coll_pair = scheme_make_pair(coll_string, scheme_null);
1033 MZ_GC_CHECK();
Bram Moolenaar75676462013-01-30 14:55:42 +01001034 config = scheme_current_config();
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00001035 MZ_GC_CHECK();
1036 scheme_set_param(config, MZCONFIG_COLLECTION_PATHS, coll_pair);
1037 MZ_GC_CHECK();
1038 MZ_GC_UNREG();
1039 }
Bram Moolenaare2a49d82007-07-06 17:43:08 +00001040# endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001041#endif
Bram Moolenaar555b2802005-05-19 21:08:39 +00001042#ifdef HAVE_SANDBOX
Bram Moolenaar555b2802005-05-19 21:08:39 +00001043 {
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00001044 Scheme_Object *make_security_guard = NULL;
1045 MZ_GC_DECL_REG(1);
1046 MZ_GC_VAR_IN_REG(0, make_security_guard);
1047 MZ_GC_REG();
1048
1049#if MZSCHEME_VERSION_MAJOR < 400
1050 {
1051 Scheme_Object *make_security_guard_symbol = NULL;
1052 MZ_GC_DECL_REG(1);
1053 MZ_GC_VAR_IN_REG(0, make_security_guard_symbol);
1054 MZ_GC_REG();
1055 make_security_guard_symbol = scheme_intern_symbol("make-security-guard");
1056 MZ_GC_CHECK();
1057 make_security_guard = scheme_lookup_global(
1058 make_security_guard_symbol, environment);
1059 MZ_GC_UNREG();
1060 }
1061#else
1062 make_security_guard = scheme_builtin_value("make-security-guard");
1063 MZ_GC_CHECK();
1064#endif
1065
1066 /* setup sandbox guards */
1067 if (make_security_guard != NULL)
1068 {
1069 Scheme_Object *args[3] = {NULL, NULL, NULL};
1070 Scheme_Object *guard = NULL;
1071 Scheme_Config *config = NULL;
1072 MZ_GC_DECL_REG(5);
1073 MZ_GC_ARRAY_VAR_IN_REG(0, args, 3);
1074 MZ_GC_VAR_IN_REG(3, guard);
1075 MZ_GC_VAR_IN_REG(4, config);
1076 MZ_GC_REG();
Bram Moolenaar75676462013-01-30 14:55:42 +01001077 config = scheme_current_config();
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00001078 MZ_GC_CHECK();
1079 args[0] = scheme_get_param(config, MZCONFIG_SECURITY_GUARD);
1080 MZ_GC_CHECK();
1081 args[1] = scheme_make_prim_w_arity(sandbox_file_guard,
1082 "sandbox-file-guard", 3, 3);
1083 args[2] = scheme_make_prim_w_arity(sandbox_network_guard,
1084 "sandbox-network-guard", 4, 4);
1085 guard = scheme_apply(make_security_guard, 3, args);
1086 MZ_GC_CHECK();
1087 scheme_set_param(config, MZCONFIG_SECURITY_GUARD, guard);
1088 MZ_GC_CHECK();
1089 MZ_GC_UNREG();
1090 }
1091 MZ_GC_UNREG();
Bram Moolenaar555b2802005-05-19 21:08:39 +00001092 }
1093#endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001094 /* Create buffer and window types for use in Scheme code */
1095 mz_buffer_type = scheme_make_type("<vim-buffer>");
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00001096 MZ_GC_CHECK();
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001097 mz_window_type = scheme_make_type("<vim-window>");
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00001098 MZ_GC_CHECK();
1099#ifdef MZ_PRECISE_GC
1100 GC_register_traversers(mz_buffer_type,
1101 buffer_size_proc, buffer_mark_proc, buffer_fixup_proc,
1102 TRUE, TRUE);
1103 GC_register_traversers(mz_window_type,
1104 window_size_proc, window_mark_proc, window_fixup_proc,
1105 TRUE, TRUE);
1106#endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001107
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00001108 make_modules();
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001109
1110 /*
1111 * setup callback to receive notifications
1112 * whether thread scheduling is (or not) required
1113 */
1114 scheme_notify_multithread = notify_multithread;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001115}
1116
1117/*
1118 * This routine is called for each new invocation of MzScheme
1119 * to make sure things are properly initialized.
1120 */
1121 static int
1122mzscheme_init(void)
1123{
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001124 if (!initialized)
1125 {
Bram Moolenaar33570922005-01-25 22:26:29 +00001126#ifdef DYNAMIC_MZSCHEME
1127 if (!mzscheme_enabled(TRUE))
1128 {
Bram Moolenaarb849e712009-06-24 15:51:37 +00001129 EMSG(_("E815: Sorry, this command is disabled, the MzScheme libraries could not be loaded."));
Bram Moolenaar33570922005-01-25 22:26:29 +00001130 return -1;
1131 }
1132#endif
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001133 startup_mzscheme();
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00001134 initialized = TRUE;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001135 }
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001136 {
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00001137 Scheme_Config *config = NULL;
1138 MZ_GC_DECL_REG(1);
1139 MZ_GC_VAR_IN_REG(0, config);
1140 MZ_GC_REG();
Bram Moolenaar75676462013-01-30 14:55:42 +01001141 config = scheme_current_config();
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00001142 MZ_GC_CHECK();
Bram Moolenaar0a1c0ec2009-12-16 18:02:47 +00001143 /* recreate ports each call effectively clearing these ones */
Bram Moolenaar75676462013-01-30 14:55:42 +01001144 curout = scheme_make_byte_string_output_port();
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00001145 MZ_GC_CHECK();
Bram Moolenaar75676462013-01-30 14:55:42 +01001146 curerr = scheme_make_byte_string_output_port();
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00001147 MZ_GC_CHECK();
1148 scheme_set_param(config, MZCONFIG_OUTPUT_PORT, curout);
1149 MZ_GC_CHECK();
1150 scheme_set_param(config, MZCONFIG_ERROR_PORT, curerr);
1151 MZ_GC_CHECK();
1152 MZ_GC_UNREG();
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001153 }
1154
1155 return 0;
1156}
1157
1158/*
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001159 *========================================================================
1160 * 2. External Interface
1161 *========================================================================
1162 */
1163
1164/*
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00001165 * Evaluate command with exception handling
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001166 */
1167 static int
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00001168eval_with_exn_handling(void *data, Scheme_Closed_Prim *what, Scheme_Object **ret)
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001169{
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00001170 Scheme_Object *value = NULL;
1171 Scheme_Object *exn = NULL;
1172 Scheme_Object *prim = NULL;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001173
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00001174 MZ_GC_DECL_REG(3);
1175 MZ_GC_VAR_IN_REG(0, value);
1176 MZ_GC_VAR_IN_REG(1, exn);
1177 MZ_GC_VAR_IN_REG(2, prim);
1178 MZ_GC_REG();
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001179
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00001180 prim = scheme_make_closed_prim_w_arity(what, data, "mzvim", 0, 0);
1181 MZ_GC_CHECK();
1182 value = _apply_thunk_catch_exceptions(prim, &exn);
1183 MZ_GC_CHECK();
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001184
1185 if (!value)
1186 {
1187 value = extract_exn_message(exn);
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001188 /* Got an exn? */
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001189 if (value)
1190 {
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00001191 scheme_display(value, curerr); /* Send to stderr-vim */
1192 MZ_GC_CHECK();
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001193 do_flush();
1194 }
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00001195 MZ_GC_UNREG();
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001196 /* `raise' was called on some arbitrary value */
1197 return FAIL;
1198 }
1199
1200 if (ret != NULL) /* if pointer to retval supported give it up */
1201 *ret = value;
1202 /* Print any result, as long as it's not a void */
1203 else if (!SCHEME_VOIDP(value))
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00001204 {
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001205 scheme_display(value, curout); /* Send to stdout-vim */
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00001206 MZ_GC_CHECK();
1207 }
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001208
1209 do_flush();
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00001210 MZ_GC_UNREG();
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001211 return OK;
1212}
1213
1214/* :mzscheme */
1215 static int
1216do_mzscheme_command(exarg_T *eap, void *data, Scheme_Closed_Prim *what)
1217{
1218 if (mzscheme_init())
1219 return FAIL;
1220
1221 range_start = eap->line1;
1222 range_end = eap->line2;
1223
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00001224 return eval_with_exn_handling(data, what, NULL);
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001225}
1226
1227/*
1228 * Routine called by VIM when deleting a buffer
1229 */
1230 void
1231mzscheme_buffer_free(buf_T *buf)
1232{
Bram Moolenaare344bea2005-09-01 20:46:49 +00001233 if (buf->b_mzscheme_ref)
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001234 {
Bram Moolenaar75676462013-01-30 14:55:42 +01001235 vim_mz_buffer *bp = NULL;
1236 MZ_GC_DECL_REG(1);
1237 MZ_GC_VAR_IN_REG(0, bp);
1238 MZ_GC_REG();
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001239
Bram Moolenaar75676462013-01-30 14:55:42 +01001240 bp = BUFFER_REF(buf);
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001241 bp->buf = INVALID_BUFFER_VALUE;
Bram Moolenaar75676462013-01-30 14:55:42 +01001242#ifndef MZ_PRECISE_GC
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001243 scheme_gc_ptr_ok(bp);
Bram Moolenaar75676462013-01-30 14:55:42 +01001244#else
1245 scheme_free_immobile_box(buf->b_mzscheme_ref);
1246#endif
1247 buf->b_mzscheme_ref = NULL;
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00001248 MZ_GC_CHECK();
Bram Moolenaar75676462013-01-30 14:55:42 +01001249 MZ_GC_UNREG();
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001250 }
1251}
1252
1253/*
1254 * Routine called by VIM when deleting a Window
1255 */
1256 void
1257mzscheme_window_free(win_T *win)
1258{
Bram Moolenaare344bea2005-09-01 20:46:49 +00001259 if (win->w_mzscheme_ref)
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001260 {
Bram Moolenaar75676462013-01-30 14:55:42 +01001261 vim_mz_window *wp = NULL;
1262 MZ_GC_DECL_REG(1);
1263 MZ_GC_VAR_IN_REG(0, wp);
1264 MZ_GC_REG();
1265 wp = WINDOW_REF(win);
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001266 wp->win = INVALID_WINDOW_VALUE;
Bram Moolenaar75676462013-01-30 14:55:42 +01001267#ifndef MZ_PRECISE_GC
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001268 scheme_gc_ptr_ok(wp);
Bram Moolenaar75676462013-01-30 14:55:42 +01001269#else
1270 scheme_free_immobile_box(win->w_mzscheme_ref);
1271#endif
1272 win->w_mzscheme_ref = NULL;
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00001273 MZ_GC_CHECK();
Bram Moolenaar75676462013-01-30 14:55:42 +01001274 MZ_GC_UNREG();
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001275 }
1276}
1277
1278/*
1279 * ":mzscheme" (or ":mz")
1280 */
1281 void
1282ex_mzscheme(exarg_T *eap)
1283{
1284 char_u *script;
1285
1286 script = script_get(eap, eap->arg);
1287 if (!eap->skip)
1288 {
1289 if (script == NULL)
1290 do_mzscheme_command(eap, eap->arg, do_eval);
1291 else
1292 {
1293 do_mzscheme_command(eap, script, do_eval);
1294 vim_free(script);
1295 }
1296 }
1297}
1298
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001299 static Scheme_Object *
Bram Moolenaar64404472010-06-26 06:24:45 +02001300do_load(void *data, int noargc UNUSED, Scheme_Object **noargv UNUSED)
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001301{
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00001302 Scheme_Object *expr = NULL;
1303 Scheme_Object *result = NULL;
1304 char *file = NULL;
1305 Port_Info *pinfo = (Port_Info *)data;
1306
1307 MZ_GC_DECL_REG(3);
1308 MZ_GC_VAR_IN_REG(0, expr);
1309 MZ_GC_VAR_IN_REG(1, result);
1310 MZ_GC_VAR_IN_REG(2, file);
1311 MZ_GC_REG();
1312
1313 file = (char *)scheme_malloc_fail_ok(scheme_malloc_atomic, MAXPATHL + 1);
1314 MZ_GC_CHECK();
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001315
1316 /* make Vim expansion */
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00001317 expand_env((char_u *)pinfo->name, (char_u *)file, MAXPATHL);
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001318 pinfo->port = scheme_open_input_file(file, "mzfile");
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00001319 MZ_GC_CHECK();
1320 scheme_count_lines(pinfo->port); /* to get accurate read error location*/
1321 MZ_GC_CHECK();
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001322
1323 /* Like REPL but print only last result */
1324 while (!SCHEME_EOFP(expr = scheme_read(pinfo->port)))
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00001325 {
1326 result = scheme_eval(expr, environment);
1327 MZ_GC_CHECK();
1328 }
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001329
Bram Moolenaar0a1c0ec2009-12-16 18:02:47 +00001330 /* errors will be caught in do_mzscheme_command and ex_mzfile */
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001331 scheme_close_input_port(pinfo->port);
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00001332 MZ_GC_CHECK();
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001333 pinfo->port = NULL;
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00001334 MZ_GC_UNREG();
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001335 return result;
1336}
1337
1338/* :mzfile */
1339 void
1340ex_mzfile(exarg_T *eap)
1341{
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00001342 Port_Info pinfo = {NULL, NULL};
1343
1344 MZ_GC_DECL_REG(1);
1345 MZ_GC_VAR_IN_REG(0, pinfo.port);
1346 MZ_GC_REG();
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001347
1348 pinfo.name = (char *)eap->arg;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001349 if (do_mzscheme_command(eap, &pinfo, do_load) != OK
1350 && pinfo.port != NULL) /* looks like port was not closed */
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00001351 {
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001352 scheme_close_input_port(pinfo.port);
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00001353 MZ_GC_CHECK();
1354 }
1355 MZ_GC_UNREG();
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001356}
1357
1358
1359/*
1360 *========================================================================
1361 * Exception handling code -- cribbed form the MzScheme sources and
1362 * Matthew Flatt's "Inside PLT MzScheme" document.
1363 *========================================================================
1364 */
1365 static void
1366init_exn_catching_apply(void)
1367{
1368 if (!exn_catching_apply)
1369 {
1370 char *e =
1371 "(lambda (thunk) "
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001372 "(with-handlers ([void (lambda (exn) (cons #f exn))]) "
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001373 "(cons #t (thunk))))";
1374
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00001375 exn_catching_apply = scheme_eval_string(e, environment);
1376 MZ_GC_CHECK();
1377 exn_p = scheme_builtin_value("exn?");
1378 MZ_GC_CHECK();
1379 exn_message = scheme_builtin_value("exn-message");
1380 MZ_GC_CHECK();
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001381 }
1382}
1383
1384/*
1385 * This function applies a thunk, returning the Scheme value if there's
1386 * no exception, otherwise returning NULL and setting *exn to the raised
1387 * value (usually an exn structure).
1388 */
1389 static Scheme_Object *
1390_apply_thunk_catch_exceptions(Scheme_Object *f, Scheme_Object **exn)
1391{
1392 Scheme_Object *v;
1393
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001394 v = _scheme_apply(exn_catching_apply, 1, &f);
1395 /* v is a pair: (cons #t value) or (cons #f exn) */
1396
1397 if (SCHEME_TRUEP(SCHEME_CAR(v)))
1398 return SCHEME_CDR(v);
1399 else
1400 {
1401 *exn = SCHEME_CDR(v);
1402 return NULL;
1403 }
1404}
1405
1406 static Scheme_Object *
1407extract_exn_message(Scheme_Object *v)
1408{
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001409 if (SCHEME_TRUEP(_scheme_apply(exn_p, 1, &v)))
1410 return _scheme_apply(exn_message, 1, &v);
1411 else
1412 return NULL; /* Not an exn structure */
1413}
1414
1415 static Scheme_Object *
Bram Moolenaar64404472010-06-26 06:24:45 +02001416do_eval(void *s, int noargc UNUSED, Scheme_Object **noargv UNUSED)
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001417{
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00001418 return scheme_eval_string_all((char *)s, environment, TRUE);
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001419}
1420
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001421/*
1422 *========================================================================
1423 * 3. MzScheme I/O Handlers
1424 *========================================================================
1425 */
1426 static void
Bram Moolenaar64404472010-06-26 06:24:45 +02001427do_intrnl_output(char *mesg, int error)
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001428{
1429 char *p, *prev;
1430
1431 prev = mesg;
1432 p = strchr(prev, '\n');
1433 while (p)
1434 {
1435 *p = '\0';
1436 if (error)
1437 EMSG(prev);
1438 else
1439 MSG(prev);
1440 prev = p + 1;
1441 p = strchr(prev, '\n');
1442 }
1443
1444 if (error)
1445 EMSG(prev);
1446 else
1447 MSG(prev);
1448}
1449
1450 static void
Bram Moolenaar75676462013-01-30 14:55:42 +01001451do_output(char *mesg, OUTPUT_LEN_TYPE len UNUSED)
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001452{
Bram Moolenaar02e14d62012-11-28 15:37:51 +01001453 /* TODO: use len, the string may not be NUL terminated */
Bram Moolenaar64404472010-06-26 06:24:45 +02001454 do_intrnl_output(mesg, 0);
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001455}
1456
1457 static void
Bram Moolenaar64404472010-06-26 06:24:45 +02001458do_err_output(char *mesg)
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001459{
Bram Moolenaar64404472010-06-26 06:24:45 +02001460 do_intrnl_output(mesg, 1);
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001461}
1462
1463 static void
1464do_printf(char *format, ...)
1465{
Bram Moolenaar64404472010-06-26 06:24:45 +02001466 do_intrnl_output(format, 1);
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001467}
1468
1469 static void
1470do_flush(void)
1471{
1472 char *buff;
Bram Moolenaar75676462013-01-30 14:55:42 +01001473 OUTPUT_LEN_TYPE length;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001474
Bram Moolenaar75676462013-01-30 14:55:42 +01001475 buff = scheme_get_sized_byte_string_output(curerr, &length);
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00001476 MZ_GC_CHECK();
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001477 if (length)
1478 {
Bram Moolenaar64404472010-06-26 06:24:45 +02001479 do_err_output(buff);
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001480 return;
1481 }
1482
Bram Moolenaar75676462013-01-30 14:55:42 +01001483 buff = scheme_get_sized_byte_string_output(curout, &length);
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00001484 MZ_GC_CHECK();
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001485 if (length)
1486 do_output(buff, length);
1487}
1488
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001489/*
1490 *========================================================================
1491 * 4. Implementation of the Vim Features for MzScheme
1492 *========================================================================
1493 */
1494
1495/* (command {command-string}) */
1496 static Scheme_Object *
1497vim_command(void *data, int argc, Scheme_Object **argv)
1498{
1499 Vim_Prim *prim = (Vim_Prim *)data;
Bram Moolenaar75676462013-01-30 14:55:42 +01001500 Scheme_Object *cmd = NULL;
1501 MZ_GC_DECL_REG(1);
1502 MZ_GC_VAR_IN_REG(0, cmd);
1503 MZ_GC_REG();
1504 cmd = GUARANTEED_STRING_ARG(prim->name, 0);
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001505
1506 /* may be use do_cmdline_cmd? */
Bram Moolenaar75676462013-01-30 14:55:42 +01001507 do_cmdline(BYTE_STRING_VALUE(cmd), NULL, NULL, DOCMD_NOWAIT|DOCMD_VERBOSE);
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001508 update_screen(VALID);
1509
Bram Moolenaar75676462013-01-30 14:55:42 +01001510 MZ_GC_UNREG();
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001511 raise_if_error();
1512 return scheme_void;
1513}
1514
1515/* (eval {expr-string}) */
1516 static Scheme_Object *
Bram Moolenaard2142212013-01-30 17:41:50 +01001517vim_eval(void *data UNUSED, int argc UNUSED, Scheme_Object **argv UNUSED)
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001518{
1519#ifdef FEAT_EVAL
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00001520 Vim_Prim *prim = (Vim_Prim *)data;
Bram Moolenaar75676462013-01-30 14:55:42 +01001521 Scheme_Object *result = NULL;
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00001522 typval_T *vim_result;
Bram Moolenaar75676462013-01-30 14:55:42 +01001523 Scheme_Object *expr = NULL;
1524 MZ_GC_DECL_REG(2);
1525 MZ_GC_VAR_IN_REG(0, result);
1526 MZ_GC_VAR_IN_REG(1, expr);
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00001527 MZ_GC_REG();
Bram Moolenaar75676462013-01-30 14:55:42 +01001528 expr = GUARANTEED_STRING_ARG(prim->name, 0);
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00001529
Bram Moolenaar75676462013-01-30 14:55:42 +01001530 vim_result = eval_expr(BYTE_STRING_VALUE(expr), NULL);
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001531
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00001532 if (vim_result == NULL)
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001533 raise_vim_exn(_("invalid expression"));
1534
Bram Moolenaar75676462013-01-30 14:55:42 +01001535 result = vim_to_mzscheme(vim_result);
1536 MZ_GC_CHECK();
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00001537 free_tv(vim_result);
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001538
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00001539 MZ_GC_UNREG();
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001540 return result;
1541#else
1542 raise_vim_exn(_("expressions disabled at compile time"));
1543 /* unreachable */
1544 return scheme_false;
1545#endif
1546}
1547
1548/* (range-start) */
1549 static Scheme_Object *
Bram Moolenaar64404472010-06-26 06:24:45 +02001550get_range_start(void *data UNUSED, int argc UNUSED, Scheme_Object **argv UNUSED)
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001551{
1552 return scheme_make_integer(range_start);
1553}
1554
1555/* (range-end) */
1556 static Scheme_Object *
Bram Moolenaar64404472010-06-26 06:24:45 +02001557get_range_end(void *data UNUSED, int argc UNUSED, Scheme_Object **argv UNUSED)
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001558{
1559 return scheme_make_integer(range_end);
1560}
1561
1562/* (beep) */
1563 static Scheme_Object *
Bram Moolenaar64404472010-06-26 06:24:45 +02001564mzscheme_beep(void *data UNUSED, int argc UNUSED, Scheme_Object **argv UNUSED)
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001565{
1566 vim_beep();
1567 return scheme_void;
1568}
1569
1570static Scheme_Object *M_global = NULL;
1571
1572/* (get-option {option-name}) [buffer/window] */
1573 static Scheme_Object *
1574get_option(void *data, int argc, Scheme_Object **argv)
1575{
1576 Vim_Prim *prim = (Vim_Prim *)data;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001577 long value;
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00001578 char *strval;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001579 int rc;
Bram Moolenaar75676462013-01-30 14:55:42 +01001580 Scheme_Object *rval = NULL;
1581 Scheme_Object *name = NULL;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001582 int opt_flags = 0;
1583 buf_T *save_curb = curbuf;
1584 win_T *save_curw = curwin;
1585
Bram Moolenaar75676462013-01-30 14:55:42 +01001586 MZ_GC_DECL_REG(2);
1587 MZ_GC_VAR_IN_REG(0, rval);
1588 MZ_GC_VAR_IN_REG(1, name);
1589 MZ_GC_REG();
1590
1591 name = GUARANTEED_STRING_ARG(prim->name, 0);
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001592
1593 if (argc > 1)
1594 {
1595 if (M_global == NULL)
1596 {
1597 MZ_REGISTER_STATIC(M_global);
1598 M_global = scheme_intern_symbol("global");
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00001599 MZ_GC_CHECK();
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001600 }
1601
1602 if (argv[1] == M_global)
1603 opt_flags = OPT_GLOBAL;
1604 else if (SCHEME_VIMBUFFERP(argv[1]))
1605 {
1606 curbuf = get_valid_buffer(argv[1]);
1607 opt_flags = OPT_LOCAL;
1608 }
1609 else if (SCHEME_VIMWINDOWP(argv[1]))
1610 {
1611 win_T *win = get_valid_window(argv[1]);
1612
1613 curwin = win;
1614 curbuf = win->w_buffer;
1615 opt_flags = OPT_LOCAL;
1616 }
1617 else
1618 scheme_wrong_type(prim->name, "vim-buffer/window", 1, argc, argv);
1619 }
1620
Bram Moolenaar75676462013-01-30 14:55:42 +01001621 rc = get_option_value(BYTE_STRING_VALUE(name), &value, (char_u **)&strval, opt_flags);
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001622 curbuf = save_curb;
1623 curwin = save_curw;
1624
1625 switch (rc)
1626 {
1627 case 1:
Bram Moolenaar75676462013-01-30 14:55:42 +01001628 MZ_GC_UNREG();
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001629 return scheme_make_integer_value(value);
1630 case 0:
Bram Moolenaar75676462013-01-30 14:55:42 +01001631 rval = scheme_make_byte_string(strval);
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00001632 MZ_GC_CHECK();
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001633 vim_free(strval);
Bram Moolenaar75676462013-01-30 14:55:42 +01001634 MZ_GC_UNREG();
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001635 return rval;
1636 case -1:
1637 case -2:
Bram Moolenaar75676462013-01-30 14:55:42 +01001638 MZ_GC_UNREG();
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001639 raise_vim_exn(_("hidden option"));
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001640 case -3:
Bram Moolenaar75676462013-01-30 14:55:42 +01001641 MZ_GC_UNREG();
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001642 raise_vim_exn(_("unknown option"));
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001643 }
1644 /* unreachable */
1645 return scheme_void;
1646}
1647
1648/* (set-option {option-changing-string} [buffer/window]) */
1649 static Scheme_Object *
1650set_option(void *data, int argc, Scheme_Object **argv)
1651{
Bram Moolenaar75676462013-01-30 14:55:42 +01001652 char_u *command = NULL;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001653 int opt_flags = 0;
1654 buf_T *save_curb = curbuf;
1655 win_T *save_curw = curwin;
1656 Vim_Prim *prim = (Vim_Prim *)data;
Bram Moolenaar75676462013-01-30 14:55:42 +01001657 Scheme_Object *cmd = NULL;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001658
Bram Moolenaar75676462013-01-30 14:55:42 +01001659 MZ_GC_DECL_REG(1);
1660 MZ_GC_VAR_IN_REG(0, cmd);
1661 MZ_GC_REG();
1662 cmd = GUARANTEED_STRING_ARG(prim->name, 0);
1663
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001664 if (argc > 1)
1665 {
1666 if (M_global == NULL)
1667 {
1668 MZ_REGISTER_STATIC(M_global);
1669 M_global = scheme_intern_symbol("global");
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00001670 MZ_GC_CHECK();
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001671 }
1672
1673 if (argv[1] == M_global)
1674 opt_flags = OPT_GLOBAL;
1675 else if (SCHEME_VIMBUFFERP(argv[1]))
1676 {
1677 curbuf = get_valid_buffer(argv[1]);
1678 opt_flags = OPT_LOCAL;
1679 }
1680 else if (SCHEME_VIMWINDOWP(argv[1]))
1681 {
1682 win_T *win = get_valid_window(argv[1]);
1683 curwin = win;
1684 curbuf = win->w_buffer;
1685 opt_flags = OPT_LOCAL;
1686 }
1687 else
1688 scheme_wrong_type(prim->name, "vim-buffer/window", 1, argc, argv);
1689 }
1690
1691 /* do_set can modify cmd, make copy */
Bram Moolenaar75676462013-01-30 14:55:42 +01001692 command = vim_strsave(BYTE_STRING_VALUE(cmd));
1693 MZ_GC_UNREG();
1694 do_set(command, opt_flags);
1695 vim_free(command);
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001696 update_screen(NOT_VALID);
1697 curbuf = save_curb;
1698 curwin = save_curw;
1699 raise_if_error();
1700 return scheme_void;
1701}
1702
1703/*
1704 *===========================================================================
1705 * 5. Vim Window-related Manipulation Functions
1706 *===========================================================================
1707 */
1708
1709/* (curr-win) */
1710 static Scheme_Object *
Bram Moolenaar64404472010-06-26 06:24:45 +02001711get_curr_win(void *data UNUSED, int argc UNUSED, Scheme_Object **argv UNUSED)
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001712{
1713 return (Scheme_Object *)get_vim_curr_window();
1714}
1715
1716/* (win-count) */
1717 static Scheme_Object *
Bram Moolenaar64404472010-06-26 06:24:45 +02001718get_window_count(void *data UNUSED, int argc UNUSED, Scheme_Object **argv UNUSED)
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001719{
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001720 int n = 0;
Bram Moolenaard2142212013-01-30 17:41:50 +01001721#ifdef FEAT_WINDOWS
1722 win_T *w;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001723
Bram Moolenaarf740b292006-02-16 22:11:02 +00001724 for (w = firstwin; w != NULL; w = w->w_next)
Bram Moolenaard2142212013-01-30 17:41:50 +01001725#endif
Bram Moolenaarf740b292006-02-16 22:11:02 +00001726 ++n;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001727 return scheme_make_integer(n);
1728}
1729
1730/* (get-win-list [buffer]) */
1731 static Scheme_Object *
1732get_window_list(void *data, int argc, Scheme_Object **argv)
1733{
1734 Vim_Prim *prim = (Vim_Prim *)data;
1735 vim_mz_buffer *buf;
1736 Scheme_Object *list;
Bram Moolenaard2142212013-01-30 17:41:50 +01001737 win_T *w = firstwin;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001738
1739 buf = get_buffer_arg(prim->name, 0, argc, argv);
1740 list = scheme_null;
1741
Bram Moolenaard2142212013-01-30 17:41:50 +01001742#ifdef FEAT_WINDOWS
1743 for ( ; w != NULL; w = w->w_next)
1744#endif
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001745 if (w->w_buffer == buf->buf)
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00001746 {
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001747 list = scheme_make_pair(window_new(w), list);
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00001748 MZ_GC_CHECK();
1749 }
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001750
1751 return list;
1752}
1753
1754 static Scheme_Object *
1755window_new(win_T *win)
1756{
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00001757 vim_mz_window *self = NULL;
1758
1759 MZ_GC_DECL_REG(1);
1760 MZ_GC_VAR_IN_REG(0, self);
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001761
1762 /* We need to handle deletion of windows underneath us.
Bram Moolenaare344bea2005-09-01 20:46:49 +00001763 * If we add a "w_mzscheme_ref" field to the win_T structure,
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001764 * then we can get at it in win_free() in vim.
1765 *
1766 * On a win_free() we set the Scheme object's win_T *field
1767 * to an invalid value. We trap all uses of a window
1768 * object, and reject them if the win_T *field is invalid.
1769 */
Bram Moolenaare344bea2005-09-01 20:46:49 +00001770 if (win->w_mzscheme_ref != NULL)
Bram Moolenaar75676462013-01-30 14:55:42 +01001771 return (Scheme_Object *)WINDOW_REF(win);
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001772
Bram Moolenaar75676462013-01-30 14:55:42 +01001773 MZ_GC_REG();
1774 self = scheme_malloc_fail_ok(scheme_malloc_tagged, sizeof(vim_mz_window));
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001775 vim_memset(self, 0, sizeof(vim_mz_window));
Bram Moolenaar75676462013-01-30 14:55:42 +01001776#ifndef MZ_PRECISE_GC
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001777 scheme_dont_gc_ptr(self); /* because win isn't visible to GC */
Bram Moolenaar75676462013-01-30 14:55:42 +01001778#else
1779 win->w_mzscheme_ref = scheme_malloc_immobile_box(NULL);
1780#endif
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00001781 MZ_GC_CHECK();
Bram Moolenaar75676462013-01-30 14:55:42 +01001782 WINDOW_REF(win) = self;
1783 MZ_GC_CHECK();
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001784 self->win = win;
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00001785 self->so.type = mz_window_type;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001786
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00001787 MZ_GC_UNREG();
Bram Moolenaar75676462013-01-30 14:55:42 +01001788 return (Scheme_Object *)self;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001789}
1790
1791/* (get-win-num [window]) */
1792 static Scheme_Object *
Bram Moolenaard2142212013-01-30 17:41:50 +01001793get_window_num(void *data UNUSED, int argc UNUSED, Scheme_Object **argv UNUSED)
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001794{
Bram Moolenaard2142212013-01-30 17:41:50 +01001795 int nr = 1;
1796#ifdef FEAT_WINDOWS
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001797 Vim_Prim *prim = (Vim_Prim *)data;
1798 win_T *win = get_window_arg(prim->name, 0, argc, argv)->win;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001799 win_T *wp;
1800
1801 for (wp = firstwin; wp != win; wp = wp->w_next)
Bram Moolenaard2142212013-01-30 17:41:50 +01001802#endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001803 ++nr;
1804
1805 return scheme_make_integer(nr);
1806}
1807
1808/* (get-win-by-num {windownum}) */
1809 static Scheme_Object *
1810get_window_by_num(void *data, int argc, Scheme_Object **argv)
1811{
1812 Vim_Prim *prim = (Vim_Prim *)data;
Bram Moolenaard2142212013-01-30 17:41:50 +01001813 win_T *win = firstwin;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001814 int fnum;
1815
1816 fnum = SCHEME_INT_VAL(GUARANTEE_INTEGER(prim->name, 0));
1817 if (fnum < 1)
1818 scheme_signal_error(_("window index is out of range"));
1819
Bram Moolenaard2142212013-01-30 17:41:50 +01001820#ifdef FEAT_WINDOWS
1821 for ( ; win != NULL; win = win->w_next, --fnum)
1822#endif
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00001823 if (fnum == 1) /* to be 1-based */
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001824 return window_new(win);
1825
1826 return scheme_false;
1827}
1828
1829/* (get-win-buffer [window]) */
1830 static Scheme_Object *
1831get_window_buffer(void *data, int argc, Scheme_Object **argv)
1832{
1833 Vim_Prim *prim = (Vim_Prim *)data;
1834 vim_mz_window *win = get_window_arg(prim->name, 0, argc, argv);
1835
1836 return buffer_new(win->win->w_buffer);
1837}
1838
1839/* (get-win-height [window]) */
1840 static Scheme_Object *
1841get_window_height(void *data, int argc, Scheme_Object **argv)
1842{
1843 Vim_Prim *prim = (Vim_Prim *)data;
1844 vim_mz_window *win = get_window_arg(prim->name, 0, argc, argv);
1845
1846 return scheme_make_integer(win->win->w_height);
1847}
1848
1849/* (set-win-height {height} [window]) */
1850 static Scheme_Object *
1851set_window_height(void *data, int argc, Scheme_Object **argv)
1852{
1853 Vim_Prim *prim = (Vim_Prim *)data;
1854 vim_mz_window *win;
1855 win_T *savewin;
1856 int height;
1857
1858 win = get_window_arg(prim->name, 1, argc, argv);
1859 height = SCHEME_INT_VAL(GUARANTEE_INTEGER(prim->name, 0));
1860
1861#ifdef FEAT_GUI
1862 need_mouse_correct = TRUE;
1863#endif
1864
1865 savewin = curwin;
1866 curwin = win->win;
1867 win_setheight(height);
1868 curwin = savewin;
1869
1870 raise_if_error();
1871 return scheme_void;
1872}
1873
1874#ifdef FEAT_VERTSPLIT
1875/* (get-win-width [window]) */
1876 static Scheme_Object *
1877get_window_width(void *data, int argc, Scheme_Object **argv)
1878{
1879 Vim_Prim *prim = (Vim_Prim *)data;
1880 vim_mz_window *win = get_window_arg(prim->name, 0, argc, argv);
1881
1882 return scheme_make_integer(W_WIDTH(win->win));
1883}
1884
1885/* (set-win-width {width} [window]) */
1886 static Scheme_Object *
1887set_window_width(void *data, int argc, Scheme_Object **argv)
1888{
1889 Vim_Prim *prim = (Vim_Prim *)data;
1890 vim_mz_window *win;
1891 win_T *savewin;
1892 int width = 0;
1893
1894 win = get_window_arg(prim->name, 1, argc, argv);
1895 width = SCHEME_INT_VAL(GUARANTEE_INTEGER(prim->name, 0));
1896
1897# ifdef FEAT_GUI
1898 need_mouse_correct = TRUE;
1899# endif
1900
1901 savewin = curwin;
1902 curwin = win->win;
1903 win_setwidth(width);
1904 curwin = savewin;
1905
1906 raise_if_error();
1907 return scheme_void;
1908}
1909#endif
1910
1911/* (get-cursor [window]) -> (line . col) */
1912 static Scheme_Object *
1913get_cursor(void *data, int argc, Scheme_Object **argv)
1914{
1915 Vim_Prim *prim = (Vim_Prim *)data;
1916 vim_mz_window *win;
1917 pos_T pos;
1918
1919 win = get_window_arg(prim->name, 0, argc, argv);
1920 pos = win->win->w_cursor;
1921 return scheme_make_pair(scheme_make_integer_value((long)pos.lnum),
1922 scheme_make_integer_value((long)pos.col + 1));
1923}
1924
1925/* (set-cursor (line . col) [window]) */
1926 static Scheme_Object *
1927set_cursor(void *data, int argc, Scheme_Object **argv)
1928{
1929 Vim_Prim *prim = (Vim_Prim *)data;
1930 vim_mz_window *win;
1931 long lnum = 0;
1932 long col = 0;
1933
Bram Moolenaar555b2802005-05-19 21:08:39 +00001934#ifdef HAVE_SANDBOX
1935 sandbox_check();
1936#endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001937 win = get_window_arg(prim->name, 1, argc, argv);
1938 GUARANTEE_PAIR(prim->name, 0);
1939
1940 if (!SCHEME_INTP(SCHEME_CAR(argv[0]))
1941 || !SCHEME_INTP(SCHEME_CDR(argv[0])))
1942 scheme_wrong_type(prim->name, "integer pair", 0, argc, argv);
1943
1944 lnum = SCHEME_INT_VAL(SCHEME_CAR(argv[0]));
1945 col = SCHEME_INT_VAL(SCHEME_CDR(argv[0])) - 1;
1946
1947 check_line_range(lnum, win->win->w_buffer);
1948 /* don't know how to catch invalid column value */
1949
1950 win->win->w_cursor.lnum = lnum;
1951 win->win->w_cursor.col = col;
1952 update_screen(VALID);
1953
1954 raise_if_error();
1955 return scheme_void;
1956}
1957/*
1958 *===========================================================================
1959 * 6. Vim Buffer-related Manipulation Functions
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001960 *===========================================================================
1961 */
1962
1963/* (open-buff {filename}) */
1964 static Scheme_Object *
1965mzscheme_open_buffer(void *data, int argc, Scheme_Object **argv)
1966{
1967 Vim_Prim *prim = (Vim_Prim *)data;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001968 int num = 0;
Bram Moolenaar75676462013-01-30 14:55:42 +01001969 Scheme_Object *onum = NULL;
1970 Scheme_Object *buf = NULL;
1971 Scheme_Object *fname;
1972
1973 MZ_GC_DECL_REG(3);
1974 MZ_GC_VAR_IN_REG(0, onum);
1975 MZ_GC_VAR_IN_REG(1, buf);
1976 MZ_GC_VAR_IN_REG(2, fname);
1977 MZ_GC_REG();
1978 fname = GUARANTEED_STRING_ARG(prim->name, 0);
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001979
Bram Moolenaar555b2802005-05-19 21:08:39 +00001980#ifdef HAVE_SANDBOX
1981 sandbox_check();
1982#endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001983 /* TODO make open existing file */
Bram Moolenaar75676462013-01-30 14:55:42 +01001984 num = buflist_add(BYTE_STRING_VALUE(fname), BLN_LISTED | BLN_CURBUF);
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001985
1986 if (num == 0)
1987 raise_vim_exn(_("couldn't open buffer"));
1988
1989 onum = scheme_make_integer(num);
Bram Moolenaar75676462013-01-30 14:55:42 +01001990 buf = get_buffer_by_num(data, 1, &onum);
1991 MZ_GC_UNREG();
1992 return buf;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00001993}
1994
1995/* (get-buff-by-num {buffernum}) */
1996 static Scheme_Object *
1997get_buffer_by_num(void *data, int argc, Scheme_Object **argv)
1998{
1999 Vim_Prim *prim = (Vim_Prim *)data;
2000 buf_T *buf;
2001 int fnum;
2002
2003 fnum = SCHEME_INT_VAL(GUARANTEE_INTEGER(prim->name, 0));
2004
2005 for (buf = firstbuf; buf; buf = buf->b_next)
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002006 if (buf->b_fnum == fnum)
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002007 return buffer_new(buf);
2008
2009 return scheme_false;
2010}
2011
2012/* (get-buff-by-name {buffername}) */
2013 static Scheme_Object *
2014get_buffer_by_name(void *data, int argc, Scheme_Object **argv)
2015{
2016 Vim_Prim *prim = (Vim_Prim *)data;
2017 buf_T *buf;
Bram Moolenaar75676462013-01-30 14:55:42 +01002018 Scheme_Object *buffer = NULL;
2019 Scheme_Object *fname = NULL;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002020
Bram Moolenaar75676462013-01-30 14:55:42 +01002021 MZ_GC_DECL_REG(2);
2022 MZ_GC_VAR_IN_REG(0, buffer);
2023 MZ_GC_VAR_IN_REG(1, fname);
2024 MZ_GC_REG();
2025 fname = GUARANTEED_STRING_ARG(prim->name, 0);
2026 buffer = scheme_false;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002027
2028 for (buf = firstbuf; buf; buf = buf->b_next)
Bram Moolenaar75676462013-01-30 14:55:42 +01002029 {
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002030 if (buf->b_ffname == NULL || buf->b_sfname == NULL)
2031 /* empty string */
2032 {
Bram Moolenaar75676462013-01-30 14:55:42 +01002033 if (BYTE_STRING_VALUE(fname)[0] == NUL)
2034 buffer = buffer_new(buf);
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002035 }
Bram Moolenaar75676462013-01-30 14:55:42 +01002036 else if (!fnamecmp(buf->b_ffname, BYTE_STRING_VALUE(fname))
2037 || !fnamecmp(buf->b_sfname, BYTE_STRING_VALUE(fname)))
2038 {
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002039 /* either short or long filename matches */
Bram Moolenaar75676462013-01-30 14:55:42 +01002040 buffer = buffer_new(buf);
2041 }
2042 }
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002043
Bram Moolenaar75676462013-01-30 14:55:42 +01002044 MZ_GC_UNREG();
2045 return buffer;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002046}
2047
2048/* (get-next-buff [buffer]) */
2049 static Scheme_Object *
2050get_next_buffer(void *data, int argc, Scheme_Object **argv)
2051{
2052 Vim_Prim *prim = (Vim_Prim *)data;
2053 buf_T *buf = get_buffer_arg(prim->name, 0, argc, argv)->buf;
2054
2055 if (buf->b_next == NULL)
2056 return scheme_false;
2057 else
2058 return buffer_new(buf->b_next);
2059}
2060
2061/* (get-prev-buff [buffer]) */
2062 static Scheme_Object *
2063get_prev_buffer(void *data, int argc, Scheme_Object **argv)
2064{
2065 Vim_Prim *prim = (Vim_Prim *)data;
2066 buf_T *buf = get_buffer_arg(prim->name, 0, argc, argv)->buf;
2067
2068 if (buf->b_prev == NULL)
2069 return scheme_false;
2070 else
2071 return buffer_new(buf->b_prev);
2072}
2073
2074/* (get-buff-num [buffer]) */
2075 static Scheme_Object *
2076get_buffer_num(void *data, int argc, Scheme_Object **argv)
2077{
2078 Vim_Prim *prim = (Vim_Prim *)data;
2079 vim_mz_buffer *buf = get_buffer_arg(prim->name, 0, argc, argv);
2080
2081 return scheme_make_integer(buf->buf->b_fnum);
2082}
2083
2084/* (buff-count) */
2085 static Scheme_Object *
Bram Moolenaar64404472010-06-26 06:24:45 +02002086get_buffer_count(void *data UNUSED, int argc UNUSED, Scheme_Object **argv UNUSED)
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002087{
2088 buf_T *b;
2089 int n = 0;
2090
2091 for (b = firstbuf; b; b = b->b_next) ++n;
2092 return scheme_make_integer(n);
2093}
2094
2095/* (get-buff-name [buffer]) */
2096 static Scheme_Object *
2097get_buffer_name(void *data, int argc, Scheme_Object **argv)
2098{
2099 Vim_Prim *prim = (Vim_Prim *)data;
2100 vim_mz_buffer *buf = get_buffer_arg(prim->name, 0, argc, argv);
2101
Bram Moolenaar75676462013-01-30 14:55:42 +01002102 return scheme_make_byte_string((char *)buf->buf->b_ffname);
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002103}
2104
2105/* (curr-buff) */
2106 static Scheme_Object *
Bram Moolenaar64404472010-06-26 06:24:45 +02002107get_curr_buffer(void *data UNUSED, int argc UNUSED, Scheme_Object **argv UNUSED)
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002108{
2109 return (Scheme_Object *)get_vim_curr_buffer();
2110}
2111
2112 static Scheme_Object *
2113buffer_new(buf_T *buf)
2114{
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00002115 vim_mz_buffer *self = NULL;
2116
2117 MZ_GC_DECL_REG(1);
2118 MZ_GC_VAR_IN_REG(0, self);
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002119
2120 /* We need to handle deletion of buffers underneath us.
Bram Moolenaare344bea2005-09-01 20:46:49 +00002121 * If we add a "b_mzscheme_ref" field to the buf_T structure,
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002122 * then we can get at it in buf_freeall() in vim.
2123 */
Bram Moolenaare344bea2005-09-01 20:46:49 +00002124 if (buf->b_mzscheme_ref)
Bram Moolenaar75676462013-01-30 14:55:42 +01002125 return (Scheme_Object *)BUFFER_REF(buf);
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002126
Bram Moolenaar75676462013-01-30 14:55:42 +01002127 MZ_GC_REG();
2128 self = scheme_malloc_fail_ok(scheme_malloc_tagged, sizeof(vim_mz_buffer));
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002129 vim_memset(self, 0, sizeof(vim_mz_buffer));
Bram Moolenaar75676462013-01-30 14:55:42 +01002130#ifndef MZ_PRECISE_GC
2131 scheme_dont_gc_ptr(self); /* because buf isn't visible to GC */
2132#else
2133 buf->b_mzscheme_ref = scheme_malloc_immobile_box(NULL);
2134#endif
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00002135 MZ_GC_CHECK();
Bram Moolenaar75676462013-01-30 14:55:42 +01002136 BUFFER_REF(buf) = self;
2137 MZ_GC_CHECK();
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002138 self->buf = buf;
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00002139 self->so.type = mz_buffer_type;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002140
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00002141 MZ_GC_UNREG();
Bram Moolenaar75676462013-01-30 14:55:42 +01002142 return (Scheme_Object *)self;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002143}
2144
2145/*
2146 * (get-buff-size [buffer])
2147 *
2148 * Get the size (number of lines) in the current buffer.
2149 */
2150 static Scheme_Object *
2151get_buffer_size(void *data, int argc, Scheme_Object **argv)
2152{
2153 Vim_Prim *prim = (Vim_Prim *)data;
2154 vim_mz_buffer *buf = get_buffer_arg(prim->name, 0, argc, argv);
2155
2156 return scheme_make_integer(buf->buf->b_ml.ml_line_count);
2157}
2158
2159/*
2160 * (get-buff-line {linenr} [buffer])
2161 *
2162 * Get a line from the specified buffer. The line number is
2163 * in Vim format (1-based). The line is returned as a MzScheme
2164 * string object.
2165 */
2166 static Scheme_Object *
2167get_buffer_line(void *data, int argc, Scheme_Object **argv)
2168{
2169 Vim_Prim *prim = (Vim_Prim *)data;
2170 vim_mz_buffer *buf;
2171 int linenr;
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00002172 char_u *line;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002173
2174 buf = get_buffer_arg(prim->name, 1, argc, argv);
2175 linenr = SCHEME_INT_VAL(GUARANTEE_INTEGER(prim->name, 0));
2176 line = ml_get_buf(buf->buf, (linenr_T)linenr, FALSE);
2177
2178 raise_if_error();
Bram Moolenaar75676462013-01-30 14:55:42 +01002179 return scheme_make_byte_string((char *)line);
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002180}
2181
2182
2183/*
2184 * (get-buff-line-list {start} {end} [buffer])
2185 *
2186 * Get a list of lines from the specified buffer. The line numbers
2187 * are in Vim format (1-based). The range is from lo up to, but not
2188 * including, hi. The list is returned as a list of string objects.
2189 */
2190 static Scheme_Object *
2191get_buffer_line_list(void *data, int argc, Scheme_Object **argv)
2192{
2193 Vim_Prim *prim = (Vim_Prim *)data;
2194 vim_mz_buffer *buf;
2195 int i, hi, lo, n;
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00002196 Scheme_Object *list = NULL;
2197
2198 MZ_GC_DECL_REG(1);
2199 MZ_GC_VAR_IN_REG(0, list);
2200 MZ_GC_REG();
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002201
2202 buf = get_buffer_arg(prim->name, 2, argc, argv);
2203 list = scheme_null;
2204 hi = SCHEME_INT_VAL(GUARANTEE_INTEGER(prim->name, 1));
2205 lo = SCHEME_INT_VAL(GUARANTEE_INTEGER(prim->name, 0));
2206
2207 /*
2208 * Handle some error conditions
2209 */
2210 if (lo < 0)
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002211 lo = 0;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002212
2213 if (hi < 0)
2214 hi = 0;
2215 if (hi < lo)
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002216 hi = lo;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002217
2218 n = hi - lo;
2219
2220 for (i = n; i >= 0; --i)
2221 {
Bram Moolenaar75676462013-01-30 14:55:42 +01002222 Scheme_Object *str = scheme_make_byte_string(
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002223 (char *)ml_get_buf(buf->buf, (linenr_T)(lo+i), FALSE));
2224 raise_if_error();
2225
2226 /* Set the list item */
2227 list = scheme_make_pair(str, list);
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00002228 MZ_GC_CHECK();
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002229 }
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00002230 MZ_GC_UNREG();
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002231 return list;
2232}
2233
2234/*
2235 * (set-buff-line {linenr} {string/#f} [buffer])
2236 *
2237 * Replace a line in the specified buffer. The line number is
2238 * in Vim format (1-based). The replacement line is given as
2239 * an MzScheme string object. The object is checked for validity
2240 * and correct format. An exception is thrown if the values are not
2241 * the correct format.
2242 *
2243 * It returns a Scheme Object that indicates the length of the
2244 * string changed.
2245 */
2246 static Scheme_Object *
2247set_buffer_line(void *data, int argc, Scheme_Object **argv)
2248{
Bram Moolenaar0a1c0ec2009-12-16 18:02:47 +00002249 /* First of all, we check the value of the supplied MzScheme object.
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002250 * There are three cases:
2251 * 1. #f - this is a deletion.
2252 * 2. A string - this is a replacement.
2253 * 3. Anything else - this is an error.
2254 */
2255 Vim_Prim *prim = (Vim_Prim *)data;
2256 vim_mz_buffer *buf;
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00002257 Scheme_Object *line = NULL;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002258 char *save;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002259 int n;
2260
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00002261 MZ_GC_DECL_REG(1);
2262 MZ_GC_VAR_IN_REG(0, line);
2263 MZ_GC_REG();
2264
Bram Moolenaar555b2802005-05-19 21:08:39 +00002265#ifdef HAVE_SANDBOX
2266 sandbox_check();
2267#endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002268 n = SCHEME_INT_VAL(GUARANTEE_INTEGER(prim->name, 0));
2269 if (!SCHEME_STRINGP(argv[1]) && !SCHEME_FALSEP(argv[1]))
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002270 scheme_wrong_type(prim->name, "string or #f", 1, argc, argv);
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002271 line = argv[1];
2272 buf = get_buffer_arg(prim->name, 2, argc, argv);
2273
2274 check_line_range(n, buf->buf);
2275
2276 if (SCHEME_FALSEP(line))
2277 {
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00002278 buf_T *savebuf = curbuf;
2279
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002280 curbuf = buf->buf;
2281
2282 if (u_savedel((linenr_T)n, 1L) == FAIL)
2283 {
2284 curbuf = savebuf;
2285 raise_vim_exn(_("cannot save undo information"));
2286 }
2287 else if (ml_delete((linenr_T)n, FALSE) == FAIL)
2288 {
2289 curbuf = savebuf;
2290 raise_vim_exn(_("cannot delete line"));
2291 }
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002292 if (buf->buf == curwin->w_buffer)
2293 mz_fix_cursor(n, n + 1, -1);
Bram Moolenaarcdcaa582009-07-09 18:06:49 +00002294 deleted_lines_mark((linenr_T)n, 1L);
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002295
2296 curbuf = savebuf;
2297
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00002298 MZ_GC_UNREG();
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002299 raise_if_error();
2300 return scheme_void;
2301 }
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002302 else
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00002303 {
2304 /* Otherwise it's a line */
2305 buf_T *savebuf = curbuf;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002306
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00002307 save = string_to_line(line);
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002308
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00002309 curbuf = buf->buf;
2310
2311 if (u_savesub((linenr_T)n) == FAIL)
2312 {
2313 curbuf = savebuf;
2314 vim_free(save);
2315 raise_vim_exn(_("cannot save undo information"));
2316 }
2317 else if (ml_replace((linenr_T)n, (char_u *)save, TRUE) == FAIL)
2318 {
2319 curbuf = savebuf;
2320 vim_free(save);
2321 raise_vim_exn(_("cannot replace line"));
2322 }
2323 else
2324 {
2325 vim_free(save);
2326 changed_bytes((linenr_T)n, 0);
2327 }
2328
2329 curbuf = savebuf;
2330
2331 /* Check that the cursor is not beyond the end of the line now. */
2332 if (buf->buf == curwin->w_buffer)
2333 check_cursor_col();
2334
2335 MZ_GC_UNREG();
2336 raise_if_error();
2337 return scheme_void;
2338 }
2339}
2340
2341 static void
2342free_array(char **array)
2343{
2344 char **curr = array;
2345 while (*curr != NULL)
2346 vim_free(*curr++);
2347 vim_free(array);
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002348}
2349
2350/*
2351 * (set-buff-line-list {start} {end} {string-list/#f/null} [buffer])
2352 *
2353 * Replace a range of lines in the specified buffer. The line numbers are in
2354 * Vim format (1-based). The range is from lo up to, but not including, hi.
2355 * The replacement lines are given as a Scheme list of string objects. The
2356 * list is checked for validity and correct format.
2357 *
2358 * Errors are returned as a value of FAIL. The return value is OK on success.
2359 * If OK is returned and len_change is not NULL, *len_change is set to the
2360 * change in the buffer length.
2361 */
2362 static Scheme_Object *
2363set_buffer_line_list(void *data, int argc, Scheme_Object **argv)
2364{
2365 /* First of all, we check the type of the supplied MzScheme object.
2366 * There are three cases:
2367 * 1. #f - this is a deletion.
2368 * 2. A list - this is a replacement.
2369 * 3. Anything else - this is an error.
2370 */
2371 Vim_Prim *prim = (Vim_Prim *)data;
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00002372 vim_mz_buffer *buf = NULL;
2373 Scheme_Object *line_list = NULL;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002374 int i, old_len, new_len, hi, lo;
2375 long extra;
2376
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00002377 MZ_GC_DECL_REG(1);
2378 MZ_GC_VAR_IN_REG(0, line_list);
2379 MZ_GC_REG();
2380
Bram Moolenaar555b2802005-05-19 21:08:39 +00002381#ifdef HAVE_SANDBOX
2382 sandbox_check();
2383#endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002384 lo = SCHEME_INT_VAL(GUARANTEE_INTEGER(prim->name, 0));
2385 hi = SCHEME_INT_VAL(GUARANTEE_INTEGER(prim->name, 1));
2386 if (!SCHEME_PAIRP(argv[2])
2387 && !SCHEME_FALSEP(argv[2]) && !SCHEME_NULLP(argv[2]))
2388 scheme_wrong_type(prim->name, "list or #f", 2, argc, argv);
2389 line_list = argv[2];
2390 buf = get_buffer_arg(prim->name, 3, argc, argv);
2391 old_len = hi - lo;
2392 if (old_len < 0) /* process inverse values wisely */
2393 {
2394 i = lo;
2395 lo = hi;
2396 hi = i;
2397 old_len = -old_len;
2398 }
2399 extra = 0;
2400
2401 check_line_range(lo, buf->buf); /* inclusive */
Bram Moolenaarbae0c162007-05-10 19:30:25 +00002402 check_line_range(hi - 1, buf->buf); /* exclusive */
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002403
2404 if (SCHEME_FALSEP(line_list) || SCHEME_NULLP(line_list))
2405 {
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00002406 buf_T *savebuf = curbuf;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002407 curbuf = buf->buf;
2408
2409 if (u_savedel((linenr_T)lo, (long)old_len) == FAIL)
2410 {
2411 curbuf = savebuf;
2412 raise_vim_exn(_("cannot save undo information"));
2413 }
2414 else
2415 {
2416 for (i = 0; i < old_len; i++)
2417 if (ml_delete((linenr_T)lo, FALSE) == FAIL)
2418 {
2419 curbuf = savebuf;
2420 raise_vim_exn(_("cannot delete line"));
2421 }
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002422 if (buf->buf == curwin->w_buffer)
2423 mz_fix_cursor(lo, hi, -old_len);
Bram Moolenaarcdcaa582009-07-09 18:06:49 +00002424 deleted_lines_mark((linenr_T)lo, (long)old_len);
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002425 }
2426
2427 curbuf = savebuf;
2428
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00002429 MZ_GC_UNREG();
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002430 raise_if_error();
2431 return scheme_void;
2432 }
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00002433 else
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002434 {
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00002435 buf_T *savebuf = curbuf;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002436
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00002437 /* List */
2438 new_len = scheme_proper_list_length(line_list);
2439 MZ_GC_CHECK();
2440 if (new_len < 0) /* improper or cyclic list */
2441 scheme_wrong_type(prim->name, "proper list",
2442 2, argc, argv);
2443 else
2444 {
2445 char **array = NULL;
2446 Scheme_Object *line = NULL;
2447 Scheme_Object *rest = NULL;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002448
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00002449 MZ_GC_DECL_REG(2);
2450 MZ_GC_VAR_IN_REG(0, line);
2451 MZ_GC_VAR_IN_REG(1, rest);
2452 MZ_GC_REG();
2453
Bram Moolenaar75676462013-01-30 14:55:42 +01002454 array = (char **)alloc((new_len+1)* sizeof(char *));
2455 vim_memset(array, 0, (new_len+1) * sizeof(char *));
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00002456
2457 rest = line_list;
2458 for (i = 0; i < new_len; ++i)
2459 {
2460 line = SCHEME_CAR(rest);
2461 rest = SCHEME_CDR(rest);
2462 if (!SCHEME_STRINGP(line))
2463 {
2464 free_array(array);
2465 scheme_wrong_type(prim->name, "string-list", 2, argc, argv);
2466 }
2467 array[i] = string_to_line(line);
2468 }
2469
2470 curbuf = buf->buf;
2471
2472 if (u_save((linenr_T)(lo-1), (linenr_T)hi) == FAIL)
2473 {
2474 curbuf = savebuf;
2475 free_array(array);
2476 raise_vim_exn(_("cannot save undo information"));
2477 }
2478
2479 /*
2480 * If the size of the range is reducing (ie, new_len < old_len) we
2481 * need to delete some old_len. We do this at the start, by
2482 * repeatedly deleting line "lo".
2483 */
2484 for (i = 0; i < old_len - new_len; ++i)
2485 {
2486 if (ml_delete((linenr_T)lo, FALSE) == FAIL)
2487 {
2488 curbuf = savebuf;
2489 free_array(array);
2490 raise_vim_exn(_("cannot delete line"));
2491 }
2492 extra--;
2493 }
2494
2495 /*
2496 * For as long as possible, replace the existing old_len with the
2497 * new old_len. This is a more efficient operation, as it requires
2498 * less memory allocation and freeing.
2499 */
2500 for (i = 0; i < old_len && i < new_len; i++)
2501 if (ml_replace((linenr_T)(lo+i), (char_u *)array[i], TRUE) == FAIL)
2502 {
2503 curbuf = savebuf;
2504 free_array(array);
2505 raise_vim_exn(_("cannot replace line"));
2506 }
2507
2508 /*
2509 * Now we may need to insert the remaining new_len. We don't need to
2510 * free the string passed back because MzScheme has control of that
2511 * memory.
2512 */
2513 while (i < new_len)
2514 {
2515 if (ml_append((linenr_T)(lo + i - 1),
2516 (char_u *)array[i], 0, FALSE) == FAIL)
2517 {
2518 curbuf = savebuf;
2519 free_array(array);
2520 raise_vim_exn(_("cannot insert line"));
2521 }
2522 ++i;
2523 ++extra;
2524 }
2525 MZ_GC_UNREG();
2526 free_array(array);
2527 }
2528
2529 /*
2530 * Adjust marks. Invalidate any which lie in the
2531 * changed range, and move any in the remainder of the buffer.
2532 */
2533 mark_adjust((linenr_T)lo, (linenr_T)(hi - 1), (long)MAXLNUM, (long)extra);
2534 changed_lines((linenr_T)lo, 0, (linenr_T)hi, (long)extra);
2535
2536 if (buf->buf == curwin->w_buffer)
2537 mz_fix_cursor(lo, hi, extra);
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002538 curbuf = savebuf;
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00002539
2540 MZ_GC_UNREG();
2541 raise_if_error();
2542 return scheme_void;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002543 }
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002544}
2545
2546/*
2547 * (insert-buff-line-list {linenr} {string/string-list} [buffer])
2548 *
Bram Moolenaar0a1c0ec2009-12-16 18:02:47 +00002549 * Insert a number of lines into the specified buffer after the specified line.
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002550 * The line number is in Vim format (1-based). The lines to be inserted are
2551 * given as an MzScheme list of string objects or as a single string. The lines
2552 * to be added are checked for validity and correct format. Errors are
2553 * returned as a value of FAIL. The return value is OK on success.
2554 * If OK is returned and len_change is not NULL, *len_change
2555 * is set to the change in the buffer length.
2556 */
2557 static Scheme_Object *
2558insert_buffer_line_list(void *data, int argc, Scheme_Object **argv)
2559{
2560 Vim_Prim *prim = (Vim_Prim *)data;
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00002561 vim_mz_buffer *buf = NULL;
2562 Scheme_Object *list = NULL;
2563 char *str = NULL;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002564 int i, n, size;
2565
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00002566 MZ_GC_DECL_REG(1);
2567 MZ_GC_VAR_IN_REG(0, list);
2568 MZ_GC_REG();
2569
Bram Moolenaar555b2802005-05-19 21:08:39 +00002570#ifdef HAVE_SANDBOX
2571 sandbox_check();
2572#endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002573 /*
2574 * First of all, we check the type of the supplied MzScheme object.
2575 * It must be a string or a list, or the call is in error.
2576 */
2577 n = SCHEME_INT_VAL(GUARANTEE_INTEGER(prim->name, 0));
2578 list = argv[1];
2579
2580 if (!SCHEME_STRINGP(list) && !SCHEME_PAIRP(list))
2581 scheme_wrong_type(prim->name, "string or list", 1, argc, argv);
2582 buf = get_buffer_arg(prim->name, 2, argc, argv);
2583
2584 if (n != 0) /* 0 can be used in insert */
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002585 check_line_range(n, buf->buf);
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002586 if (SCHEME_STRINGP(list))
2587 {
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00002588 buf_T *savebuf = curbuf;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002589
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00002590 str = string_to_line(list);
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002591 curbuf = buf->buf;
2592
2593 if (u_save((linenr_T)n, (linenr_T)(n+1)) == FAIL)
2594 {
2595 curbuf = savebuf;
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00002596 vim_free(str);
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002597 raise_vim_exn(_("cannot save undo information"));
2598 }
2599 else if (ml_append((linenr_T)n, (char_u *)str, 0, FALSE) == FAIL)
2600 {
2601 curbuf = savebuf;
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00002602 vim_free(str);
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002603 raise_vim_exn(_("cannot insert line"));
2604 }
2605 else
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00002606 {
2607 vim_free(str);
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002608 appended_lines_mark((linenr_T)n, 1L);
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00002609 }
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002610
2611 curbuf = savebuf;
2612 update_screen(VALID);
2613
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00002614 MZ_GC_UNREG();
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002615 raise_if_error();
2616 return scheme_void;
2617 }
2618
2619 /* List */
2620 size = scheme_proper_list_length(list);
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00002621 MZ_GC_CHECK();
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002622 if (size < 0) /* improper or cyclic list */
2623 scheme_wrong_type(prim->name, "proper list",
2624 2, argc, argv);
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002625 else
2626 {
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00002627 Scheme_Object *line = NULL;
2628 Scheme_Object *rest = NULL;
2629 char **array;
2630 buf_T *savebuf = curbuf;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002631
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00002632 MZ_GC_DECL_REG(2);
2633 MZ_GC_VAR_IN_REG(0, line);
2634 MZ_GC_VAR_IN_REG(1, rest);
2635 MZ_GC_REG();
2636
Bram Moolenaar75676462013-01-30 14:55:42 +01002637 array = (char **)alloc((size+1) * sizeof(char *));
2638 vim_memset(array, 0, (size+1) * sizeof(char *));
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00002639
2640 rest = list;
2641 for (i = 0; i < size; ++i)
2642 {
2643 line = SCHEME_CAR(rest);
2644 rest = SCHEME_CDR(rest);
2645 array[i] = string_to_line(line);
2646 }
2647
2648 curbuf = buf->buf;
2649
2650 if (u_save((linenr_T)n, (linenr_T)(n + 1)) == FAIL)
2651 {
2652 curbuf = savebuf;
2653 free_array(array);
2654 raise_vim_exn(_("cannot save undo information"));
2655 }
2656 else
2657 {
2658 for (i = 0; i < size; ++i)
2659 if (ml_append((linenr_T)(n + i), (char_u *)array[i],
2660 0, FALSE) == FAIL)
2661 {
2662 curbuf = savebuf;
2663 free_array(array);
2664 raise_vim_exn(_("cannot insert line"));
2665 }
2666
2667 if (i > 0)
2668 appended_lines_mark((linenr_T)n, (long)i);
2669 }
2670 free_array(array);
2671 MZ_GC_UNREG();
2672 curbuf = savebuf;
2673 update_screen(VALID);
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002674 }
2675
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00002676 MZ_GC_UNREG();
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002677 raise_if_error();
2678 return scheme_void;
2679}
2680
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002681/*
2682 * Predicates
2683 */
2684/* (buff? obj) */
2685 static Scheme_Object *
Bram Moolenaar64404472010-06-26 06:24:45 +02002686vim_bufferp(void *data UNUSED, int argc UNUSED, Scheme_Object **argv)
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002687{
2688 if (SCHEME_VIMBUFFERP(argv[0]))
2689 return scheme_true;
2690 else
2691 return scheme_false;
2692}
2693
2694/* (win? obj) */
2695 static Scheme_Object *
Bram Moolenaar64404472010-06-26 06:24:45 +02002696vim_windowp(void *data UNUSED, int argc UNUSED, Scheme_Object **argv)
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002697{
2698 if (SCHEME_VIMWINDOWP(argv[0]))
2699 return scheme_true;
2700 else
2701 return scheme_false;
2702}
2703
2704/* (buff-valid? obj) */
2705 static Scheme_Object *
Bram Moolenaar64404472010-06-26 06:24:45 +02002706vim_buffer_validp(void *data UNUSED, int argc UNUSED, Scheme_Object **argv)
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002707{
2708 if (SCHEME_VIMBUFFERP(argv[0])
2709 && ((vim_mz_buffer *)argv[0])->buf != INVALID_BUFFER_VALUE)
2710 return scheme_true;
2711 else
2712 return scheme_false;
2713}
2714
2715/* (win-valid? obj) */
2716 static Scheme_Object *
Bram Moolenaar64404472010-06-26 06:24:45 +02002717vim_window_validp(void *data UNUSED, int argc UNUSED, Scheme_Object **argv)
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002718{
2719 if (SCHEME_VIMWINDOWP(argv[0])
2720 && ((vim_mz_window *)argv[0])->win != INVALID_WINDOW_VALUE)
2721 return scheme_true;
2722 else
2723 return scheme_false;
2724}
2725
2726/*
2727 *===========================================================================
2728 * Utilities
2729 *===========================================================================
2730 */
2731
2732/*
2733 * Convert an MzScheme string into a Vim line.
2734 *
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00002735 * All internal nulls are replaced by newline characters.
2736 * It is an error for the string to contain newline characters.
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002737 *
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00002738 * Returns pointer to Vim allocated memory
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002739 */
2740 static char *
2741string_to_line(Scheme_Object *obj)
2742{
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00002743 char *scheme_str = NULL;
2744 char *vim_str = NULL;
Bram Moolenaar75676462013-01-30 14:55:42 +01002745 OUTPUT_LEN_TYPE len;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002746 int i;
2747
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00002748 scheme_str = scheme_display_to_string(obj, &len);
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002749
2750 /* Error checking: String must not contain newlines, as we
2751 * are replacing a single line, and we must replace it with
2752 * a single line.
2753 */
Bram Moolenaar75676462013-01-30 14:55:42 +01002754 if (memchr(scheme_str, '\n', len))
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002755 scheme_signal_error(_("string cannot contain newlines"));
2756
Bram Moolenaar75676462013-01-30 14:55:42 +01002757 vim_str = (char *)alloc(len + 1);
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00002758
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002759 /* Create a copy of the string, with internal nulls replaced by
2760 * newline characters, as is the vim convention.
2761 */
2762 for (i = 0; i < len; ++i)
2763 {
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00002764 if (scheme_str[i] == '\0')
2765 vim_str[i] = '\n';
2766 else
2767 vim_str[i] = scheme_str[i];
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002768 }
2769
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00002770 vim_str[i] = '\0';
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002771
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00002772 MZ_GC_CHECK();
2773 return vim_str;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00002774}
2775
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00002776#ifdef FEAT_EVAL
2777/*
2778 * Convert Vim value into MzScheme, adopted from if_python.c
2779 */
2780 static Scheme_Object *
Bram Moolenaar75676462013-01-30 14:55:42 +01002781vim_to_mzscheme(typval_T *vim_value)
2782{
2783 Scheme_Object *result = NULL;
2784 /* hash table to store visited values to avoid infinite loops */
2785 Scheme_Hash_Table *visited = NULL;
2786
2787 MZ_GC_DECL_REG(2);
2788 MZ_GC_VAR_IN_REG(0, result);
2789 MZ_GC_VAR_IN_REG(1, visited);
2790 MZ_GC_REG();
2791
2792 visited = scheme_make_hash_table(SCHEME_hash_ptr);
2793 MZ_GC_CHECK();
2794
2795 result = vim_to_mzscheme_impl(vim_value, 1, visited);
2796
2797 MZ_GC_UNREG();
2798 return result;
2799}
2800
2801 static Scheme_Object *
2802vim_to_mzscheme_impl(typval_T *vim_value, int depth, Scheme_Hash_Table *visited)
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00002803{
2804 Scheme_Object *result = NULL;
2805 int new_value = TRUE;
2806
Bram Moolenaar75676462013-01-30 14:55:42 +01002807 MZ_GC_DECL_REG(2);
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00002808 MZ_GC_VAR_IN_REG(0, result);
Bram Moolenaar75676462013-01-30 14:55:42 +01002809 MZ_GC_VAR_IN_REG(1, visited);
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00002810 MZ_GC_REG();
2811
2812 /* Avoid infinite recursion */
2813 if (depth > 100)
2814 {
2815 MZ_GC_UNREG();
2816 return scheme_void;
2817 }
2818
2819 /* Check if we run into a recursive loop. The item must be in visited
2820 * then and we can use it again.
2821 */
2822 result = scheme_hash_get(visited, (Scheme_Object *)vim_value);
2823 MZ_GC_CHECK();
2824 if (result != NULL) /* found, do nothing */
2825 new_value = FALSE;
2826 else if (vim_value->v_type == VAR_STRING)
2827 {
Bram Moolenaar75676462013-01-30 14:55:42 +01002828 result = scheme_make_byte_string((char *)vim_value->vval.v_string);
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00002829 MZ_GC_CHECK();
2830 }
2831 else if (vim_value->v_type == VAR_NUMBER)
2832 {
2833 result = scheme_make_integer((long)vim_value->vval.v_number);
2834 MZ_GC_CHECK();
2835 }
2836# ifdef FEAT_FLOAT
2837 else if (vim_value->v_type == VAR_FLOAT)
2838 {
2839 result = scheme_make_double((double)vim_value->vval.v_float);
2840 MZ_GC_CHECK();
2841 }
2842# endif
2843 else if (vim_value->v_type == VAR_LIST)
2844 {
2845 list_T *list = vim_value->vval.v_list;
2846 listitem_T *curr;
2847
2848 if (list == NULL || list->lv_first == NULL)
2849 result = scheme_null;
2850 else
2851 {
2852 Scheme_Object *obj = NULL;
2853
2854 MZ_GC_DECL_REG(1);
2855 MZ_GC_VAR_IN_REG(0, obj);
2856 MZ_GC_REG();
2857
2858 curr = list->lv_last;
Bram Moolenaar75676462013-01-30 14:55:42 +01002859 obj = vim_to_mzscheme_impl(&curr->li_tv, depth + 1, visited);
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00002860 result = scheme_make_pair(obj, scheme_null);
2861 MZ_GC_CHECK();
2862
2863 while (curr != list->lv_first)
2864 {
2865 curr = curr->li_prev;
Bram Moolenaar75676462013-01-30 14:55:42 +01002866 obj = vim_to_mzscheme_impl(&curr->li_tv, depth + 1, visited);
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00002867 result = scheme_make_pair(obj, result);
2868 MZ_GC_CHECK();
2869 }
2870 }
2871 MZ_GC_UNREG();
2872 }
2873 else if (vim_value->v_type == VAR_DICT)
2874 {
2875 Scheme_Object *key = NULL;
2876 Scheme_Object *obj = NULL;
2877
2878 MZ_GC_DECL_REG(2);
2879 MZ_GC_VAR_IN_REG(0, key);
2880 MZ_GC_VAR_IN_REG(1, obj);
2881 MZ_GC_REG();
2882
2883 result = (Scheme_Object *)scheme_make_hash_table(SCHEME_hash_ptr);
2884 MZ_GC_CHECK();
2885 if (vim_value->vval.v_dict != NULL)
2886 {
2887 hashtab_T *ht = &vim_value->vval.v_dict->dv_hashtab;
2888 long_u todo = ht->ht_used;
2889 hashitem_T *hi;
2890 dictitem_T *di;
2891
2892 for (hi = ht->ht_array; todo > 0; ++hi)
2893 {
2894 if (!HASHITEM_EMPTY(hi))
2895 {
2896 --todo;
2897
2898 di = dict_lookup(hi);
Bram Moolenaar75676462013-01-30 14:55:42 +01002899 obj = vim_to_mzscheme_impl(&di->di_tv, depth + 1, visited);
2900 key = scheme_make_byte_string((char *)hi->hi_key);
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00002901 MZ_GC_CHECK();
2902 scheme_hash_set((Scheme_Hash_Table *)result, key, obj);
2903 MZ_GC_CHECK();
2904 }
2905 }
2906 }
2907 MZ_GC_UNREG();
2908 }
Bram Moolenaar75676462013-01-30 14:55:42 +01002909 else if (vim_value->v_type == VAR_FUNC)
2910 {
2911 Scheme_Object *funcname = NULL;
2912
2913 MZ_GC_DECL_REG(1);
2914 MZ_GC_VAR_IN_REG(0, funcname);
2915 MZ_GC_REG();
2916
2917 funcname = scheme_make_byte_string((char *)vim_value->vval.v_string);
2918 MZ_GC_CHECK();
2919 result = scheme_make_closed_prim_w_arity(vim_funcref, funcname,
2920 (const char *)BYTE_STRING_VALUE(funcname), 0, -1);
2921 MZ_GC_CHECK();
2922
2923 MZ_GC_UNREG();
2924 }
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00002925 else
2926 {
2927 result = scheme_void;
2928 new_value = FALSE;
2929 }
2930 if (new_value)
2931 {
2932 scheme_hash_set(visited, (Scheme_Object *)vim_value, result);
2933 MZ_GC_CHECK();
2934 }
2935 MZ_GC_UNREG();
2936 return result;
2937}
Bram Moolenaar7e506b62010-01-19 15:55:06 +01002938
2939 static int
Bram Moolenaar75676462013-01-30 14:55:42 +01002940mzscheme_to_vim(Scheme_Object *obj, typval_T *tv)
2941{
2942 int i, status;
2943 Scheme_Hash_Table *visited = NULL;
2944
2945 MZ_GC_DECL_REG(2);
2946 MZ_GC_VAR_IN_REG(0, obj);
2947 MZ_GC_VAR_IN_REG(1, visited);
2948 MZ_GC_REG();
2949
2950 visited = scheme_make_hash_table(SCHEME_hash_ptr);
2951 MZ_GC_CHECK();
2952
2953 status = mzscheme_to_vim_impl(obj, tv, 1, visited);
2954 for (i = 0; i < visited->size; ++i)
2955 {
2956 /* free up remembered objects */
2957 if (visited->vals[i] != NULL)
2958 free_tv((typval_T *)visited->vals[i]);
2959 }
2960
2961 MZ_GC_UNREG();
2962 return status;
2963}
2964 static int
2965mzscheme_to_vim_impl(Scheme_Object *obj, typval_T *tv, int depth,
Bram Moolenaar7e506b62010-01-19 15:55:06 +01002966 Scheme_Hash_Table *visited)
2967{
2968 int status = OK;
2969 typval_T *found;
Bram Moolenaar75676462013-01-30 14:55:42 +01002970
2971 MZ_GC_DECL_REG(2);
2972 MZ_GC_VAR_IN_REG(0, obj);
2973 MZ_GC_VAR_IN_REG(1, visited);
2974 MZ_GC_REG();
2975
Bram Moolenaar7e506b62010-01-19 15:55:06 +01002976 MZ_GC_CHECK();
2977 if (depth > 100) /* limit the deepest recursion level */
2978 {
2979 tv->v_type = VAR_NUMBER;
2980 tv->vval.v_number = 0;
2981 return FAIL;
2982 }
2983
2984 found = (typval_T *)scheme_hash_get(visited, obj);
2985 if (found != NULL)
2986 copy_tv(found, tv);
2987 else if (SCHEME_VOIDP(obj))
2988 {
2989 tv->v_type = VAR_NUMBER;
2990 tv->vval.v_number = 0;
2991 }
2992 else if (SCHEME_INTP(obj))
2993 {
2994 tv->v_type = VAR_NUMBER;
2995 tv->vval.v_number = SCHEME_INT_VAL(obj);
2996 }
2997 else if (SCHEME_BOOLP(obj))
2998 {
2999 tv->v_type = VAR_NUMBER;
3000 tv->vval.v_number = SCHEME_TRUEP(obj);
3001 }
3002# ifdef FEAT_FLOAT
3003 else if (SCHEME_DBLP(obj))
3004 {
3005 tv->v_type = VAR_FLOAT;
3006 tv->vval.v_float = SCHEME_DBL_VAL(obj);
3007 }
3008# endif
Bram Moolenaar75676462013-01-30 14:55:42 +01003009 else if (SCHEME_BYTE_STRINGP(obj))
Bram Moolenaar7e506b62010-01-19 15:55:06 +01003010 {
3011 tv->v_type = VAR_STRING;
Bram Moolenaar75676462013-01-30 14:55:42 +01003012 tv->vval.v_string = vim_strsave(BYTE_STRING_VALUE(obj));
Bram Moolenaar7e506b62010-01-19 15:55:06 +01003013 }
Bram Moolenaar75676462013-01-30 14:55:42 +01003014# if MZSCHEME_VERSION_MAJOR >= 299
3015 else if (SCHEME_CHAR_STRINGP(obj))
3016 {
3017 Scheme_Object *tmp = NULL;
3018 MZ_GC_DECL_REG(1);
3019 MZ_GC_VAR_IN_REG(0, tmp);
3020 MZ_GC_REG();
3021
3022 tmp = scheme_char_string_to_byte_string(obj);
3023 tv->v_type = VAR_STRING;
3024 tv->vval.v_string = vim_strsave(BYTE_STRING_VALUE(tmp));
3025 MZ_GC_UNREG();
3026 }
3027#endif
Bram Moolenaar7e506b62010-01-19 15:55:06 +01003028 else if (SCHEME_VECTORP(obj) || SCHEME_NULLP(obj)
3029 || SCHEME_PAIRP(obj) || SCHEME_MUTABLE_PAIRP(obj))
3030 {
3031 list_T *list = list_alloc();
3032 if (list == NULL)
3033 status = FAIL;
3034 else
3035 {
3036 int i;
3037 Scheme_Object *curr = NULL;
3038 Scheme_Object *cval = NULL;
3039 /* temporary var to hold current element of vectors and pairs */
3040 typval_T *v;
3041
3042 MZ_GC_DECL_REG(2);
3043 MZ_GC_VAR_IN_REG(0, curr);
3044 MZ_GC_VAR_IN_REG(1, cval);
3045 MZ_GC_REG();
3046
3047 tv->v_type = VAR_LIST;
3048 tv->vval.v_list = list;
3049 ++list->lv_refcount;
3050
3051 v = (typval_T *)alloc(sizeof(typval_T));
3052 if (v == NULL)
3053 status = FAIL;
3054 else
3055 {
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02003056 /* add the value in advance to allow handling of self-referential
Bram Moolenaar7e506b62010-01-19 15:55:06 +01003057 * data structures */
3058 typval_T *visited_tv = (typval_T *)alloc(sizeof(typval_T));
3059 copy_tv(tv, visited_tv);
3060 scheme_hash_set(visited, obj, (Scheme_Object *)visited_tv);
3061
3062 if (SCHEME_VECTORP(obj))
3063 {
3064 for (i = 0; i < SCHEME_VEC_SIZE(obj); ++i)
3065 {
3066 cval = SCHEME_VEC_ELS(obj)[i];
Bram Moolenaar75676462013-01-30 14:55:42 +01003067 status = mzscheme_to_vim_impl(cval, v, depth + 1, visited);
Bram Moolenaar7e506b62010-01-19 15:55:06 +01003068 if (status == FAIL)
3069 break;
3070 status = list_append_tv(list, v);
3071 clear_tv(v);
3072 if (status == FAIL)
3073 break;
3074 }
3075 }
3076 else if (SCHEME_PAIRP(obj) || SCHEME_MUTABLE_PAIRP(obj))
3077 {
3078 for (curr = obj;
3079 SCHEME_PAIRP(curr) || SCHEME_MUTABLE_PAIRP(curr);
3080 curr = SCHEME_CDR(curr))
3081 {
3082 cval = SCHEME_CAR(curr);
Bram Moolenaar75676462013-01-30 14:55:42 +01003083 status = mzscheme_to_vim_impl(cval, v, depth + 1, visited);
Bram Moolenaar7e506b62010-01-19 15:55:06 +01003084 if (status == FAIL)
3085 break;
3086 status = list_append_tv(list, v);
3087 clear_tv(v);
3088 if (status == FAIL)
3089 break;
3090 }
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02003091 /* improper list not terminated with null
Bram Moolenaar7e506b62010-01-19 15:55:06 +01003092 * need to handle the last element */
3093 if (status == OK && !SCHEME_NULLP(curr))
3094 {
Bram Moolenaar75676462013-01-30 14:55:42 +01003095 status = mzscheme_to_vim_impl(cval, v, depth + 1, visited);
Bram Moolenaar7e506b62010-01-19 15:55:06 +01003096 if (status == OK)
3097 {
3098 status = list_append_tv(list, v);
3099 clear_tv(v);
3100 }
3101 }
3102 }
3103 /* nothing to do for scheme_null */
3104 vim_free(v);
3105 }
3106 MZ_GC_UNREG();
3107 }
3108 }
3109 else if (SCHEME_HASHTP(obj))
3110 {
3111 int i;
3112 dict_T *dict;
3113 Scheme_Object *key = NULL;
3114 Scheme_Object *val = NULL;
3115
3116 MZ_GC_DECL_REG(2);
3117 MZ_GC_VAR_IN_REG(0, key);
3118 MZ_GC_VAR_IN_REG(1, val);
3119 MZ_GC_REG();
3120
3121 dict = dict_alloc();
3122 if (dict == NULL)
3123 status = FAIL;
3124 else
3125 {
3126 typval_T *visited_tv = (typval_T *)alloc(sizeof(typval_T));
3127
3128 tv->v_type = VAR_DICT;
3129 tv->vval.v_dict = dict;
3130 ++dict->dv_refcount;
3131
3132 copy_tv(tv, visited_tv);
3133 scheme_hash_set(visited, obj, (Scheme_Object *)visited_tv);
3134
3135 for (i = 0; i < ((Scheme_Hash_Table *)obj)->size; ++i)
3136 {
3137 if (((Scheme_Hash_Table *) obj)->vals[i] != NULL)
3138 {
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02003139 /* generate item for `display'ed Scheme key */
Bram Moolenaar7e506b62010-01-19 15:55:06 +01003140 dictitem_T *item = dictitem_alloc((char_u *)string_to_line(
3141 ((Scheme_Hash_Table *) obj)->keys[i]));
3142 /* convert Scheme val to Vim and add it to the dict */
Bram Moolenaar75676462013-01-30 14:55:42 +01003143 if (mzscheme_to_vim_impl(((Scheme_Hash_Table *) obj)->vals[i],
Bram Moolenaar7e506b62010-01-19 15:55:06 +01003144 &item->di_tv, depth + 1, visited) == FAIL
3145 || dict_add(dict, item) == FAIL)
3146 {
3147 dictitem_free(item);
3148 status = FAIL;
3149 break;
3150 }
3151 }
3152
3153 }
3154 }
3155 MZ_GC_UNREG();
3156 }
3157 else
3158 {
3159 /* `display' any other value to string */
3160 tv->v_type = VAR_STRING;
3161 tv->vval.v_string = (char_u *)string_to_line(obj);
3162 }
Bram Moolenaar75676462013-01-30 14:55:42 +01003163 MZ_GC_UNREG();
Bram Moolenaar7e506b62010-01-19 15:55:06 +01003164 return status;
3165}
3166
Bram Moolenaar75676462013-01-30 14:55:42 +01003167/* Scheme prim procedure wrapping Vim funcref */
3168 static Scheme_Object *
3169vim_funcref(void *name, int argc, Scheme_Object **argv)
3170{
3171 int i;
3172 typval_T args;
3173 int status = OK;
3174 Scheme_Object *result = NULL;
3175 list_T *list = list_alloc();
3176
3177 MZ_GC_DECL_REG(1);
3178 MZ_GC_VAR_IN_REG(0, result);
3179 MZ_GC_REG();
3180
3181 result = scheme_void;
3182 if (list == NULL)
3183 status = FAIL;
3184 else
3185 {
3186 args.v_type = VAR_LIST;
3187 args.vval.v_list = list;
3188 ++list->lv_refcount;
3189 for (i = 0; status == OK && i < argc; ++i)
3190 {
3191 typval_T *v = (typval_T *)alloc(sizeof(typval_T));
3192 if (v == NULL)
3193 status = FAIL;
3194 else
3195 {
3196 status = mzscheme_to_vim(argv[i], v);
3197 if (status == OK)
3198 {
3199 status = list_append_tv(list, v);
3200 clear_tv(v);
3201 }
3202 vim_free(v);
3203 }
3204 }
3205 if (status == OK)
3206 {
3207 typval_T ret;
3208 ret.v_type = VAR_UNKNOWN;
3209
3210 mzscheme_call_vim(BYTE_STRING_VALUE((Scheme_Object *)name), &args, &ret);
3211 MZ_GC_CHECK();
3212 result = vim_to_mzscheme(&ret);
3213 clear_tv(&ret);
3214 MZ_GC_CHECK();
3215 }
3216 }
3217 clear_tv(&args);
3218 MZ_GC_UNREG();
3219 if (status != OK)
3220 raise_vim_exn(_("error converting Scheme values to Vim"));
3221 else
3222 raise_if_error();
3223 return result;
3224}
3225
Bram Moolenaar7e506b62010-01-19 15:55:06 +01003226 void
3227do_mzeval(char_u *str, typval_T *rettv)
3228{
Bram Moolenaar7e506b62010-01-19 15:55:06 +01003229 Scheme_Object *ret = NULL;
Bram Moolenaar7e506b62010-01-19 15:55:06 +01003230
Bram Moolenaar75676462013-01-30 14:55:42 +01003231 MZ_GC_DECL_REG(1);
Bram Moolenaar7e506b62010-01-19 15:55:06 +01003232 MZ_GC_VAR_IN_REG(0, ret);
Bram Moolenaar7e506b62010-01-19 15:55:06 +01003233 MZ_GC_REG();
3234
3235 if (mzscheme_init())
3236 {
3237 MZ_GC_UNREG();
3238 return;
3239 }
3240
3241 MZ_GC_CHECK();
Bram Moolenaar7e506b62010-01-19 15:55:06 +01003242 if (eval_with_exn_handling(str, do_eval, &ret) == OK)
Bram Moolenaar75676462013-01-30 14:55:42 +01003243 mzscheme_to_vim(ret, rettv);
Bram Moolenaar7e506b62010-01-19 15:55:06 +01003244
3245 MZ_GC_UNREG();
3246}
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00003247#endif
3248
Bram Moolenaar325b7a22004-07-05 15:58:32 +00003249/*
3250 * Check to see whether a Vim error has been reported, or a keyboard
3251 * interrupt (from vim --> got_int) has been detected.
3252 */
3253 static int
3254vim_error_check(void)
3255{
3256 return (got_int || did_emsg);
3257}
3258
3259/*
3260 * register Scheme exn:vim
3261 */
3262 static void
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00003263register_vim_exn(void)
Bram Moolenaar325b7a22004-07-05 15:58:32 +00003264{
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00003265 int nc = 0;
3266 int i;
3267 Scheme_Object *struct_exn = NULL;
3268 Scheme_Object *exn_name = NULL;
3269
3270 MZ_GC_DECL_REG(2);
3271 MZ_GC_VAR_IN_REG(0, struct_exn);
3272 MZ_GC_VAR_IN_REG(1, exn_name);
3273 MZ_GC_REG();
3274
3275 exn_name = scheme_intern_symbol("exn:vim");
3276 MZ_GC_CHECK();
3277 struct_exn = scheme_builtin_value("struct:exn");
3278 MZ_GC_CHECK();
Bram Moolenaar325b7a22004-07-05 15:58:32 +00003279
3280 if (vim_exn == NULL)
3281 vim_exn = scheme_make_struct_type(exn_name,
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00003282 struct_exn, NULL, 0, 0, NULL, NULL
Bram Moolenaar325b7a22004-07-05 15:58:32 +00003283#if MZSCHEME_VERSION_MAJOR >= 299
3284 , NULL
3285#endif
3286 );
3287
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00003288
Bram Moolenaar325b7a22004-07-05 15:58:32 +00003289 {
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00003290 Scheme_Object **tmp = NULL;
3291 Scheme_Object *exn_names[5] = {NULL, NULL, NULL, NULL, NULL};
3292 Scheme_Object *exn_values[5] = {NULL, NULL, NULL, NULL, NULL};
3293 MZ_GC_DECL_REG(6);
3294 MZ_GC_ARRAY_VAR_IN_REG(0, exn_names, 5);
3295 MZ_GC_ARRAY_VAR_IN_REG(3, exn_values, 5);
3296 MZ_GC_REG();
Bram Moolenaar325b7a22004-07-05 15:58:32 +00003297
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00003298 tmp = scheme_make_struct_names(exn_name, scheme_null, 0, &nc);
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00003299 mch_memmove(exn_names, tmp, nc * sizeof(Scheme_Object *));
3300 MZ_GC_CHECK();
Bram Moolenaar325b7a22004-07-05 15:58:32 +00003301
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00003302 tmp = scheme_make_struct_values(vim_exn, exn_names, nc, 0);
3303 mch_memmove(exn_values, tmp, nc * sizeof(Scheme_Object *));
3304 MZ_GC_CHECK();
3305
3306 for (i = 0; i < nc; i++)
3307 {
3308 scheme_add_global_symbol(exn_names[i],
3309 exn_values[i], environment);
3310 MZ_GC_CHECK();
3311 }
3312 MZ_GC_UNREG();
Bram Moolenaar325b7a22004-07-05 15:58:32 +00003313 }
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00003314 MZ_GC_UNREG();
Bram Moolenaar325b7a22004-07-05 15:58:32 +00003315}
3316
3317/*
3318 * raise exn:vim, may be with additional info string
3319 */
3320 void
3321raise_vim_exn(const char *add_info)
3322{
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00003323 char *fmt = _("Vim error: ~a");
3324 Scheme_Object *argv[2] = {NULL, NULL};
3325 Scheme_Object *exn = NULL;
Bram Moolenaar75676462013-01-30 14:55:42 +01003326 Scheme_Object *byte_string = NULL;
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00003327
Bram Moolenaar75676462013-01-30 14:55:42 +01003328 MZ_GC_DECL_REG(5);
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00003329 MZ_GC_ARRAY_VAR_IN_REG(0, argv, 2);
3330 MZ_GC_VAR_IN_REG(3, exn);
Bram Moolenaar75676462013-01-30 14:55:42 +01003331 MZ_GC_VAR_IN_REG(4, byte_string);
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00003332 MZ_GC_REG();
Bram Moolenaar325b7a22004-07-05 15:58:32 +00003333
3334 if (add_info != NULL)
3335 {
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00003336 char *c_string = NULL;
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00003337 Scheme_Object *info = NULL;
3338
3339 MZ_GC_DECL_REG(3);
3340 MZ_GC_VAR_IN_REG(0, c_string);
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00003341 MZ_GC_VAR_IN_REG(2, info);
3342 MZ_GC_REG();
3343
Bram Moolenaar75676462013-01-30 14:55:42 +01003344 info = scheme_make_byte_string(add_info);
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00003345 MZ_GC_CHECK();
Bram Moolenaar75676462013-01-30 14:55:42 +01003346 c_string = scheme_format_utf8(fmt, STRLEN(fmt), 1, &info, NULL);
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00003347 MZ_GC_CHECK();
Bram Moolenaar75676462013-01-30 14:55:42 +01003348 byte_string = scheme_make_byte_string(c_string);
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00003349 MZ_GC_CHECK();
3350 argv[0] = scheme_byte_string_to_char_string(byte_string);
Bram Moolenaar555b2802005-05-19 21:08:39 +00003351 SCHEME_SET_IMMUTABLE(argv[0]);
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00003352 MZ_GC_UNREG();
Bram Moolenaar325b7a22004-07-05 15:58:32 +00003353 }
3354 else
Bram Moolenaar75676462013-01-30 14:55:42 +01003355 {
3356 byte_string = scheme_make_byte_string(_("Vim error"));
3357 MZ_GC_CHECK();
3358 argv[0] = scheme_byte_string_to_char_string(byte_string);
3359 MZ_GC_CHECK();
3360 }
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00003361 MZ_GC_CHECK();
Bram Moolenaar325b7a22004-07-05 15:58:32 +00003362
Bram Moolenaar049377e2007-05-12 15:32:12 +00003363#if MZSCHEME_VERSION_MAJOR < 360
3364 argv[1] = scheme_current_continuation_marks();
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00003365 MZ_GC_CHECK();
Bram Moolenaar049377e2007-05-12 15:32:12 +00003366#else
Bram Moolenaarc81e5e72007-05-05 18:24:42 +00003367 argv[1] = scheme_current_continuation_marks(NULL);
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00003368 MZ_GC_CHECK();
Bram Moolenaar049377e2007-05-12 15:32:12 +00003369#endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +00003370
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00003371 exn = scheme_make_struct_instance(vim_exn, 2, argv);
3372 MZ_GC_CHECK();
3373 scheme_raise(exn);
3374 MZ_GC_UNREG();
Bram Moolenaar325b7a22004-07-05 15:58:32 +00003375}
3376
3377 void
3378raise_if_error(void)
3379{
3380 if (vim_error_check())
3381 raise_vim_exn(NULL);
3382}
3383
3384/* get buffer:
3385 * either current
3386 * or passed as argv[argnum] with checks
3387 */
3388 static vim_mz_buffer *
3389get_buffer_arg(const char *fname, int argnum, int argc, Scheme_Object **argv)
3390{
3391 vim_mz_buffer *b;
3392
3393 if (argc < argnum + 1)
3394 return get_vim_curr_buffer();
3395 if (!SCHEME_VIMBUFFERP(argv[argnum]))
3396 scheme_wrong_type(fname, "vim-buffer", argnum, argc, argv);
3397 b = (vim_mz_buffer *)argv[argnum];
3398 (void)get_valid_buffer(argv[argnum]);
3399 return b;
3400}
3401
3402/* get window:
3403 * either current
3404 * or passed as argv[argnum] with checks
3405 */
3406 static vim_mz_window *
3407get_window_arg(const char *fname, int argnum, int argc, Scheme_Object **argv)
3408{
3409 vim_mz_window *w;
3410
3411 if (argc < argnum + 1)
3412 return get_vim_curr_window();
3413 w = (vim_mz_window *)argv[argnum];
3414 if (!SCHEME_VIMWINDOWP(argv[argnum]))
3415 scheme_wrong_type(fname, "vim-window", argnum, argc, argv);
3416 (void)get_valid_window(argv[argnum]);
3417 return w;
3418}
3419
3420/* get valid Vim buffer from Scheme_Object* */
3421buf_T *get_valid_buffer(void *obj)
3422{
3423 buf_T *buf = ((vim_mz_buffer *)obj)->buf;
3424
3425 if (buf == INVALID_BUFFER_VALUE)
3426 scheme_signal_error(_("buffer is invalid"));
3427 return buf;
3428}
3429
3430/* get valid Vim window from Scheme_Object* */
3431win_T *get_valid_window(void *obj)
3432{
3433 win_T *win = ((vim_mz_window *)obj)->win;
3434 if (win == INVALID_WINDOW_VALUE)
3435 scheme_signal_error(_("window is invalid"));
3436 return win;
3437}
3438
Bram Moolenaar325b7a22004-07-05 15:58:32 +00003439 int
3440mzthreads_allowed(void)
3441{
3442 return mz_threads_allow;
3443}
3444
3445 static int
3446line_in_range(linenr_T lnum, buf_T *buf)
3447{
3448 return (lnum > 0 && lnum <= buf->b_ml.ml_line_count);
3449}
3450
3451 static void
3452check_line_range(linenr_T lnum, buf_T *buf)
3453{
3454 if (!line_in_range(lnum, buf))
3455 scheme_signal_error(_("linenr out of range"));
3456}
3457
3458/*
3459 * Check if deleting lines made the cursor position invalid
3460 * (or you'll get msg from Vim about invalid linenr).
3461 * Changed the lines from "lo" to "hi" and added "extra" lines (negative if
3462 * deleted). Got from if_python.c
3463 */
3464 static void
3465mz_fix_cursor(int lo, int hi, int extra)
3466{
3467 if (curwin->w_cursor.lnum >= lo)
3468 {
3469 /* Adjust the cursor position if it's in/after the changed
3470 * lines. */
3471 if (curwin->w_cursor.lnum >= hi)
3472 {
3473 curwin->w_cursor.lnum += extra;
3474 check_cursor_col();
3475 }
3476 else if (extra < 0)
3477 {
3478 curwin->w_cursor.lnum = lo;
3479 check_cursor();
3480 }
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00003481 else
3482 check_cursor_col();
Bram Moolenaar325b7a22004-07-05 15:58:32 +00003483 changed_cline_bef_curs();
3484 }
3485 invalidate_botline();
3486}
3487
3488static Vim_Prim prims[]=
3489{
3490 /*
3491 * Buffer-related commands
3492 */
3493 {get_buffer_line, "get-buff-line", 1, 2},
3494 {set_buffer_line, "set-buff-line", 2, 3},
3495 {get_buffer_line_list, "get-buff-line-list", 2, 3},
3496 {get_buffer_name, "get-buff-name", 0, 1},
3497 {get_buffer_num, "get-buff-num", 0, 1},
3498 {get_buffer_size, "get-buff-size", 0, 1},
3499 {set_buffer_line_list, "set-buff-line-list", 3, 4},
3500 {insert_buffer_line_list, "insert-buff-line-list", 2, 3},
3501 {get_curr_buffer, "curr-buff", 0, 0},
3502 {get_buffer_count, "buff-count", 0, 0},
3503 {get_next_buffer, "get-next-buff", 0, 1},
3504 {get_prev_buffer, "get-prev-buff", 0, 1},
3505 {mzscheme_open_buffer, "open-buff", 1, 1},
3506 {get_buffer_by_name, "get-buff-by-name", 1, 1},
3507 {get_buffer_by_num, "get-buff-by-num", 1, 1},
Bram Moolenaar325b7a22004-07-05 15:58:32 +00003508 /*
3509 * Window-related commands
3510 */
3511 {get_curr_win, "curr-win", 0, 0},
3512 {get_window_count, "win-count", 0, 0},
3513 {get_window_by_num, "get-win-by-num", 1, 1},
3514 {get_window_num, "get-win-num", 0, 1},
3515 {get_window_buffer, "get-win-buffer", 0, 1},
3516 {get_window_height, "get-win-height", 0, 1},
3517 {set_window_height, "set-win-height", 1, 2},
3518#ifdef FEAT_VERTSPLIT
3519 {get_window_width, "get-win-width", 0, 1},
3520 {set_window_width, "set-win-width", 1, 2},
3521#endif
3522 {get_cursor, "get-cursor", 0, 1},
3523 {set_cursor, "set-cursor", 1, 2},
3524 {get_window_list, "get-win-list", 0, 1},
3525 /*
3526 * Vim-related commands
3527 */
3528 {vim_command, "command", 1, 1},
3529 {vim_eval, "eval", 1, 1},
3530 {get_range_start, "range-start", 0, 0},
3531 {get_range_end, "range-end", 0, 0},
3532 {mzscheme_beep, "beep", 0, 0},
3533 {get_option, "get-option", 1, 2},
3534 {set_option, "set-option", 1, 2},
3535 /*
3536 * small utilities
3537 */
3538 {vim_bufferp, "buff?", 1, 1},
3539 {vim_windowp, "win?", 1, 1},
3540 {vim_buffer_validp, "buff-valid?", 1, 1},
3541 {vim_window_validp, "win-valid?", 1, 1}
3542};
3543
3544/* return MzScheme wrapper for curbuf */
3545 static vim_mz_buffer *
3546get_vim_curr_buffer(void)
3547{
Bram Moolenaare344bea2005-09-01 20:46:49 +00003548 if (curbuf->b_mzscheme_ref == NULL)
Bram Moolenaar325b7a22004-07-05 15:58:32 +00003549 return (vim_mz_buffer *)buffer_new(curbuf);
3550 else
Bram Moolenaar75676462013-01-30 14:55:42 +01003551 return BUFFER_REF(curbuf);
Bram Moolenaar325b7a22004-07-05 15:58:32 +00003552}
3553
3554/* return MzScheme wrapper for curwin */
3555 static vim_mz_window *
3556get_vim_curr_window(void)
3557{
Bram Moolenaare344bea2005-09-01 20:46:49 +00003558 if (curwin->w_mzscheme_ref == NULL)
Bram Moolenaar325b7a22004-07-05 15:58:32 +00003559 return (vim_mz_window *)window_new(curwin);
3560 else
Bram Moolenaar75676462013-01-30 14:55:42 +01003561 return WINDOW_REF(curwin);
Bram Moolenaar325b7a22004-07-05 15:58:32 +00003562}
3563
Bram Moolenaar325b7a22004-07-05 15:58:32 +00003564 static void
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00003565make_modules()
Bram Moolenaar325b7a22004-07-05 15:58:32 +00003566{
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00003567 int i;
3568 Scheme_Env *mod = NULL;
3569 Scheme_Object *vimext_symbol = NULL;
3570 Scheme_Object *closed_prim = NULL;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00003571
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00003572 MZ_GC_DECL_REG(3);
3573 MZ_GC_VAR_IN_REG(0, mod);
3574 MZ_GC_VAR_IN_REG(1, vimext_symbol);
3575 MZ_GC_VAR_IN_REG(2, closed_prim);
3576 MZ_GC_REG();
3577
3578 vimext_symbol = scheme_intern_symbol("vimext");
3579 MZ_GC_CHECK();
3580 mod = scheme_primitive_module(vimext_symbol, environment);
3581 MZ_GC_CHECK();
Bram Moolenaar325b7a22004-07-05 15:58:32 +00003582 /* all prims made closed so they can access their own names */
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00003583 for (i = 0; i < (int)(sizeof(prims)/sizeof(prims[0])); i++)
Bram Moolenaar325b7a22004-07-05 15:58:32 +00003584 {
3585 Vim_Prim *prim = prims + i;
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00003586 closed_prim = scheme_make_closed_prim_w_arity(prim->prim, prim, prim->name,
3587 prim->mina, prim->maxa);
3588 scheme_add_global(prim->name, closed_prim, mod);
3589 MZ_GC_CHECK();
Bram Moolenaar325b7a22004-07-05 15:58:32 +00003590 }
Bram Moolenaar325b7a22004-07-05 15:58:32 +00003591 scheme_finish_primitive_module(mod);
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00003592 MZ_GC_CHECK();
3593 MZ_GC_UNREG();
Bram Moolenaar325b7a22004-07-05 15:58:32 +00003594}
Bram Moolenaard857f0e2005-06-21 22:37:39 +00003595
Bram Moolenaar555b2802005-05-19 21:08:39 +00003596#ifdef HAVE_SANDBOX
3597static Scheme_Object *M_write = NULL;
3598static Scheme_Object *M_read = NULL;
3599static Scheme_Object *M_execute = NULL;
3600static Scheme_Object *M_delete = NULL;
3601
3602 static void
Bram Moolenaarc81e5e72007-05-05 18:24:42 +00003603sandbox_check(void)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003604{
3605 if (sandbox)
3606 raise_vim_exn(_("not allowed in the Vim sandbox"));
3607}
3608
Bram Moolenaard857f0e2005-06-21 22:37:39 +00003609/* security guards to force Vim's sandbox restrictions on MzScheme level */
Bram Moolenaar555b2802005-05-19 21:08:39 +00003610 static Scheme_Object *
Bram Moolenaar64404472010-06-26 06:24:45 +02003611sandbox_file_guard(int argc UNUSED, Scheme_Object **argv)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003612{
3613 if (sandbox)
3614 {
3615 Scheme_Object *requested_access = argv[2];
3616
3617 if (M_write == NULL)
3618 {
3619 MZ_REGISTER_STATIC(M_write);
3620 M_write = scheme_intern_symbol("write");
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00003621 MZ_GC_CHECK();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003622 }
3623 if (M_read == NULL)
3624 {
3625 MZ_REGISTER_STATIC(M_read);
3626 M_read = scheme_intern_symbol("read");
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00003627 MZ_GC_CHECK();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003628 }
3629 if (M_execute == NULL)
3630 {
3631 MZ_REGISTER_STATIC(M_execute);
3632 M_execute = scheme_intern_symbol("execute");
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00003633 MZ_GC_CHECK();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003634 }
3635 if (M_delete == NULL)
3636 {
3637 MZ_REGISTER_STATIC(M_delete);
3638 M_delete = scheme_intern_symbol("delete");
Bram Moolenaar9e70cf12009-05-26 20:59:55 +00003639 MZ_GC_CHECK();
Bram Moolenaar555b2802005-05-19 21:08:39 +00003640 }
3641
3642 while (!SCHEME_NULLP(requested_access))
3643 {
3644 Scheme_Object *item = SCHEME_CAR(requested_access);
3645 if (scheme_eq(item, M_write) || scheme_eq(item, M_read)
3646 || scheme_eq(item, M_execute) || scheme_eq(item, M_delete))
3647 {
3648 raise_vim_exn(_("not allowed in the Vim sandbox"));
3649 }
3650 requested_access = SCHEME_CDR(requested_access);
3651 }
3652 }
3653 return scheme_void;
3654}
3655
3656 static Scheme_Object *
Bram Moolenaar64404472010-06-26 06:24:45 +02003657sandbox_network_guard(int argc UNUSED, Scheme_Object **argv UNUSED)
Bram Moolenaar555b2802005-05-19 21:08:39 +00003658{
3659 return scheme_void;
3660}
3661#endif
Bram Moolenaar76b92b22006-03-24 22:46:53 +00003662
3663#endif