xref: /vim-8.2.3635/src/if_mzsch.c (revision 94688b8a)
1 /* vi:set ts=8 sts=4 sw=4 noet:
2  *
3  * MzScheme interface by Sergey Khorev <[email protected]>
4  * Based on work by Brent Fulgham <[email protected]>
5  * (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.
21  * 3. I don't use K&R-style functions. Anyways, MzScheme headers are ANSI.
22  */
23 
24 #include "vim.h"
25 
26 #include "if_mzsch.h"
27 
28 /* Only do the following when the feature is enabled.  Needed for "make
29  * depend". */
30 #if defined(FEAT_MZSCHEME) || defined(PROTO)
31 
32 #ifdef PROTO
33 typedef int Scheme_Object;
34 typedef int Scheme_Closed_Prim;
35 typedef int Scheme_Env;
36 typedef int Scheme_Hash_Table;
37 typedef int Scheme_Type;
38 typedef int Scheme_Thread;
39 typedef int Scheme_Closed_Prim;
40 typedef int mzshort;
41 typedef int Scheme_Prim;
42 typedef int HINSTANCE;
43 #endif
44 
45 /*
46  * scheme_register_tls_space is only available on 32-bit Windows until
47  * racket-6.3.  See
48  * http://docs.racket-lang.org/inside/im_memoryalloc.html?q=scheme_register_tls_space
49  */
50 #if MZSCHEME_VERSION_MAJOR >= 500 && defined(WIN32) \
51 	&& defined(USE_THREAD_LOCAL) \
52 	&& (!defined(_WIN64) || MZSCHEME_VERSION_MAJOR >= 603)
53 # define HAVE_TLS_SPACE 1
54 #endif
55 
56 /*
57  * Since version 4.x precise GC requires trampolined startup.
58  * Futures and places in version 5.x need it too.
59  */
60 #if defined(MZ_PRECISE_GC) && MZSCHEME_VERSION_MAJOR >= 400 \
61     || MZSCHEME_VERSION_MAJOR >= 500 \
62 	&& (defined(MZ_USE_FUTURES) || defined(MZ_USE_PLACES))
63 # define TRAMPOLINED_MZVIM_STARTUP
64 #endif
65 
66 /* Base data structures */
67 #define SCHEME_VIMBUFFERP(obj)  SAME_TYPE(SCHEME_TYPE(obj), mz_buffer_type)
68 #define SCHEME_VIMWINDOWP(obj)  SAME_TYPE(SCHEME_TYPE(obj), mz_window_type)
69 
70 typedef struct
71 {
72     Scheme_Object   so;
73     buf_T	    *buf;
74 } vim_mz_buffer;
75 
76 #define INVALID_BUFFER_VALUE ((buf_T *)(-1))
77 
78 typedef struct
79 {
80     Scheme_Object   so;
81     win_T	    *win;
82 } vim_mz_window;
83 
84 #define INVALID_WINDOW_VALUE ((win_T *)(-1))
85 
86 /*
87  * Prims that form MzScheme Vim interface
88  */
89 typedef struct
90 {
91     Scheme_Closed_Prim	*prim;
92     char	*name;
93     int		mina;	/* arity information */
94     int		maxa;
95 } Vim_Prim;
96 
97 typedef struct
98 {
99     char	    *name;
100     Scheme_Object   *port;
101 } Port_Info;
102 
103 /*
104  *========================================================================
105  *  Vim-Control Commands
106  *========================================================================
107  */
108 /*
109  *========================================================================
110  *  Utility functions for the vim/mzscheme interface
111  *========================================================================
112  */
113 #ifdef HAVE_SANDBOX
114 static Scheme_Object *sandbox_file_guard(int, Scheme_Object **);
115 static Scheme_Object *sandbox_network_guard(int, Scheme_Object **);
116 static void sandbox_check(void);
117 #endif
118 /*  Buffer-related commands */
119 static Scheme_Object *buffer_new(buf_T *buf);
120 static Scheme_Object *get_buffer_by_num(void *, int, Scheme_Object **);
121 static vim_mz_buffer *get_vim_curr_buffer(void);
122 
123 /*  Window-related commands */
124 static Scheme_Object *window_new(win_T *win);
125 static vim_mz_window *get_vim_curr_window(void);
126 
127 /*
128  *========================================================================
129  *  Internal Function Prototypes
130  *========================================================================
131  */
132 static int vim_error_check(void);
133 static int do_mzscheme_command(exarg_T *, void *, Scheme_Closed_Prim *what);
134 static int startup_mzscheme(void);
135 static char *string_to_line(Scheme_Object *obj);
136 #if MZSCHEME_VERSION_MAJOR >= 501
137 # define OUTPUT_LEN_TYPE intptr_t
138 #else
139 # define OUTPUT_LEN_TYPE long
140 #endif
141 static void do_output(char *mesg, OUTPUT_LEN_TYPE len);
142 static void do_printf(char *format, ...);
143 static void do_flush(void);
144 static Scheme_Object *_apply_thunk_catch_exceptions(
145 	Scheme_Object *, Scheme_Object **);
146 static Scheme_Object *extract_exn_message(Scheme_Object *v);
147 static Scheme_Object *do_eval(void *, int noargc, Scheme_Object **noargv);
148 static Scheme_Object *do_load(void *, int noargc, Scheme_Object **noargv);
149 static void register_vim_exn(void);
150 static vim_mz_buffer *get_buffer_arg(const char *fname, int argnum,
151 	int argc, Scheme_Object **argv);
152 static vim_mz_window *get_window_arg(const char *fname, int argnum,
153 	int argc, Scheme_Object **argv);
154 static int line_in_range(linenr_T, buf_T *);
155 static void check_line_range(linenr_T, buf_T *);
156 static void mz_fix_cursor(int lo, int hi, int extra);
157 
158 static int eval_with_exn_handling(void *, Scheme_Closed_Prim *,
159 	    Scheme_Object **ret);
160 static void make_modules(void);
161 static void init_exn_catching_apply(void);
162 static int mzscheme_env_main(Scheme_Env *env, int argc, char **argv);
163 static int mzscheme_init(void);
164 #ifdef FEAT_EVAL
165 static Scheme_Object *vim_to_mzscheme(typval_T *vim_value);
166 static Scheme_Object *vim_to_mzscheme_impl(typval_T *vim_value, int depth,
167 	Scheme_Hash_Table *visited);
168 static int mzscheme_to_vim(Scheme_Object *obj, typval_T *tv);
169 static int mzscheme_to_vim_impl(Scheme_Object *obj, typval_T *tv, int depth,
170 	Scheme_Hash_Table *visited);
171 static Scheme_Object *vim_funcref(void *data, int argc, Scheme_Object **argv);
172 #endif
173 
174 #ifdef MZ_PRECISE_GC
175 static int buffer_size_proc(void *obj UNUSED)
176 {
177     return gcBYTES_TO_WORDS(sizeof(vim_mz_buffer));
178 }
179 static int buffer_mark_proc(void *obj)
180 {
181     return buffer_size_proc(obj);
182 }
183 static int buffer_fixup_proc(void *obj)
184 {
185     /* apparently not needed as the object will be uncollectable while
186      * the buffer is alive
187      */
188     /*
189     vim_mz_buffer* buf = (vim_mz_buffer*) obj;
190     buf->buf->b_mzscheme_ref = GC_fixup_self(obj);
191     */
192     return buffer_size_proc(obj);
193 }
194 static int window_size_proc(void *obj UNUSED)
195 {
196     return gcBYTES_TO_WORDS(sizeof(vim_mz_window));
197 }
198 static int window_mark_proc(void *obj)
199 {
200     return window_size_proc(obj);
201 }
202 static int window_fixup_proc(void *obj)
203 {
204     /* apparently not needed as the object will be uncollectable while
205      * the window is alive
206      */
207     /*
208     vim_mz_window* win = (vim_mz_window*) obj;
209     win->win->w_mzscheme_ref = GC_fixup_self(obj);
210     */
211     return window_size_proc(obj);
212 }
213 /* with precise GC, w_mzscheme_ref and b_mzscheme_ref are immobile boxes
214  * containing pointers to a window/buffer
215  * with conservative GC these are simply pointers*/
216 # define WINDOW_REF(win) *(vim_mz_window **)((win)->w_mzscheme_ref)
217 # define BUFFER_REF(buf) *(vim_mz_buffer **)((buf)->b_mzscheme_ref)
218 #else
219 # define WINDOW_REF(win) (vim_mz_window *)((win)->w_mzscheme_ref)
220 # define BUFFER_REF(buf) (vim_mz_buffer *)((buf)->b_mzscheme_ref)
221 #endif
222 
223 #if defined(DYNAMIC_MZSCHEME) || defined(PROTO)
224 static Scheme_Object *dll_scheme_eof;
225 static Scheme_Object *dll_scheme_false;
226 static Scheme_Object *dll_scheme_void;
227 static Scheme_Object *dll_scheme_null;
228 static Scheme_Object *dll_scheme_true;
229 
230 static Scheme_Thread **dll_scheme_current_thread_ptr;
231 
232 static void (**dll_scheme_console_printf_ptr)(char *str, ...);
233 static void (**dll_scheme_console_output_ptr)(char *str, OUTPUT_LEN_TYPE len);
234 static void (**dll_scheme_notify_multithread_ptr)(int on);
235 
236 static void *(*dll_GC_malloc)(size_t size_in_bytes);
237 static void *(*dll_GC_malloc_atomic)(size_t size_in_bytes);
238 static Scheme_Env *(*dll_scheme_basic_env)(void);
239 static void (*dll_scheme_check_threads)(void);
240 static void (*dll_scheme_register_static)(void *ptr, long size);
241 static void (*dll_scheme_set_stack_base)(void *base, int no_auto_statics);
242 static void (*dll_scheme_add_global)(const char *name, Scheme_Object *val,
243 	Scheme_Env *env);
244 static void (*dll_scheme_add_global_symbol)(Scheme_Object *name,
245 	Scheme_Object *val, Scheme_Env *env);
246 static Scheme_Object *(*dll_scheme_apply)(Scheme_Object *rator, int num_rands,
247 	Scheme_Object **rands);
248 static Scheme_Object *(*dll_scheme_builtin_value)(const char *name);
249 # if MZSCHEME_VERSION_MAJOR >= 299
250 static Scheme_Object *(*dll_scheme_byte_string_to_char_string)(Scheme_Object *s);
251 static Scheme_Object *(*dll_scheme_make_path)(const char *chars);
252 # endif
253 static void (*dll_scheme_close_input_port)(Scheme_Object *port);
254 static void (*dll_scheme_count_lines)(Scheme_Object *port);
255 #if MZSCHEME_VERSION_MAJOR < 360
256 static Scheme_Object *(*dll_scheme_current_continuation_marks)(void);
257 #else
258 static Scheme_Object *(*dll_scheme_current_continuation_marks)(Scheme_Object *prompt_tag);
259 #endif
260 static void (*dll_scheme_display)(Scheme_Object *obj, Scheme_Object *port);
261 static char *(*dll_scheme_display_to_string)(Scheme_Object *obj, OUTPUT_LEN_TYPE *len);
262 static int (*dll_scheme_eq)(Scheme_Object *obj1, Scheme_Object *obj2);
263 static Scheme_Object *(*dll_scheme_do_eval)(Scheme_Object *obj,
264 	int _num_rands, Scheme_Object **rands, int val);
265 static void (*dll_scheme_dont_gc_ptr)(void *p);
266 static Scheme_Object *(*dll_scheme_eval)(Scheme_Object *obj, Scheme_Env *env);
267 static Scheme_Object *(*dll_scheme_eval_string)(const char *str,
268 	Scheme_Env *env);
269 static Scheme_Object *(*dll_scheme_eval_string_all)(const char *str,
270 	Scheme_Env *env, int all);
271 static void (*dll_scheme_finish_primitive_module)(Scheme_Env *env);
272 # if MZSCHEME_VERSION_MAJOR < 299
273 static char *(*dll_scheme_format)(char *format, int flen, int argc,
274 	Scheme_Object **argv, long *rlen);
275 # else
276 static char *(*dll_scheme_format_utf8)(char *format, int flen, int argc,
277 	Scheme_Object **argv, OUTPUT_LEN_TYPE *rlen);
278 static Scheme_Object *(*dll_scheme_get_param)(Scheme_Config *c, int pos);
279 # endif
280 static void (*dll_scheme_gc_ptr_ok)(void *p);
281 # if MZSCHEME_VERSION_MAJOR < 299
282 static char *(*dll_scheme_get_sized_string_output)(Scheme_Object *,
283 	long *len);
284 # else
285 static char *(*dll_scheme_get_sized_byte_string_output)(Scheme_Object *,
286 	OUTPUT_LEN_TYPE *len);
287 # endif
288 static Scheme_Object *(*dll_scheme_intern_symbol)(const char *name);
289 static Scheme_Object *(*dll_scheme_lookup_global)(Scheme_Object *symbol,
290 	Scheme_Env *env);
291 static Scheme_Object *(*dll_scheme_make_closed_prim_w_arity)
292     (Scheme_Closed_Prim *prim, void *data, const char *name, mzshort mina,
293      mzshort maxa);
294 static Scheme_Object *(*dll_scheme_make_integer_value)(long i);
295 static Scheme_Object *(*dll_scheme_make_pair)(Scheme_Object *car,
296 	Scheme_Object *cdr);
297 static Scheme_Object *(*dll_scheme_make_prim_w_arity)(Scheme_Prim *prim,
298 	const char *name, mzshort mina, mzshort maxa);
299 # if MZSCHEME_VERSION_MAJOR < 299
300 static Scheme_Object *(*dll_scheme_make_string)(const char *chars);
301 static Scheme_Object *(*dll_scheme_make_string_output_port)();
302 # else
303 static Scheme_Object *(*dll_scheme_make_byte_string)(const char *chars);
304 static Scheme_Object *(*dll_scheme_make_byte_string_output_port)();
305 # endif
306 static Scheme_Object *(*dll_scheme_make_struct_instance)(Scheme_Object *stype,
307 	int argc, Scheme_Object **argv);
308 static Scheme_Object **(*dll_scheme_make_struct_names)(Scheme_Object *base,
309 	Scheme_Object *field_names, int flags, int *count_out);
310 static Scheme_Object *(*dll_scheme_make_struct_type)(Scheme_Object *base,
311 	Scheme_Object *parent, Scheme_Object *inspector, int num_fields,
312 	int num_uninit_fields, Scheme_Object *uninit_val,
313 	Scheme_Object *properties
314 # if MZSCHEME_VERSION_MAJOR >= 299
315 	, Scheme_Object *guard
316 # endif
317 	);
318 static Scheme_Object **(*dll_scheme_make_struct_values)(
319 	Scheme_Object *struct_type, Scheme_Object **names, int count,
320 	int flags);
321 static Scheme_Type (*dll_scheme_make_type)(const char *name);
322 static Scheme_Object *(*dll_scheme_make_vector)(int size,
323 	Scheme_Object *fill);
324 static void *(*dll_scheme_malloc_fail_ok)(void *(*f)(size_t), size_t);
325 static Scheme_Object *(*dll_scheme_open_input_file)(const char *name,
326 	const char *who);
327 static Scheme_Env *(*dll_scheme_primitive_module)(Scheme_Object *name,
328 	Scheme_Env *for_env);
329 static int (*dll_scheme_proper_list_length)(Scheme_Object *list);
330 static void (*dll_scheme_raise)(Scheme_Object *exn);
331 static Scheme_Object *(*dll_scheme_read)(Scheme_Object *port);
332 static void (*dll_scheme_signal_error)(const char *msg, ...);
333 static void (*dll_scheme_wrong_type)(const char *name, const char *expected,
334 	int which, int argc, Scheme_Object **argv);
335 # if MZSCHEME_VERSION_MAJOR >= 299
336 static void (*dll_scheme_set_param)(Scheme_Config *c, int pos,
337 	Scheme_Object *o);
338 static Scheme_Config *(*dll_scheme_current_config)(void);
339 static Scheme_Object *(*dll_scheme_char_string_to_byte_string)
340     (Scheme_Object *s);
341 static Scheme_Object *(*dll_scheme_char_string_to_path)
342     (Scheme_Object *s);
343 static void *(*dll_scheme_set_collects_path)(Scheme_Object *p);
344 # endif
345 static Scheme_Hash_Table *(*dll_scheme_make_hash_table)(int type);
346 static void (*dll_scheme_hash_set)(Scheme_Hash_Table *table,
347 	Scheme_Object *key, Scheme_Object *value);
348 static Scheme_Object *(*dll_scheme_hash_get)(Scheme_Hash_Table *table,
349 	Scheme_Object *key);
350 static Scheme_Object *(*dll_scheme_make_double)(double d);
351 static Scheme_Object *(*dll_scheme_make_sized_byte_string)(char *chars,
352 	long len, int copy);
353 static Scheme_Object *(*dll_scheme_namespace_require)(Scheme_Object *req);
354 static Scheme_Object *(*dll_scheme_dynamic_wind)(void (*pre)(void *), Scheme_Object *(* volatile act)(void *), void (* volatile post)(void *), Scheme_Object *(*jmp_handler)(void *), void * volatile data);
355 # ifdef MZ_PRECISE_GC
356 static void *(*dll_GC_malloc_one_tagged)(size_t size_in_bytes);
357 static void (*dll_GC_register_traversers)(short tag, Size_Proc size, Mark_Proc mark, Fixup_Proc fixup, int is_constant_size, int is_atomic);
358 # endif
359 # if MZSCHEME_VERSION_MAJOR >= 400
360 static void (*dll_scheme_init_collection_paths)(Scheme_Env *global_env, Scheme_Object *extra_dirs);
361 static void **(*dll_scheme_malloc_immobile_box)(void *p);
362 static void (*dll_scheme_free_immobile_box)(void **b);
363 # endif
364 # if MZSCHEME_VERSION_MAJOR >= 500
365 #  ifdef TRAMPOLINED_MZVIM_STARTUP
366 static int (*dll_scheme_main_setup)(int no_auto_statics, Scheme_Env_Main _main, int argc, char **argv);
367 #   if defined(IMPLEMENT_THREAD_LOCAL_VIA_WIN_TLS) || MZSCHEME_VERSION_MAJOR >= 603
368 static void (*dll_scheme_register_tls_space)(void *tls_space, int _tls_index);
369 #   endif
370 #  endif
371 #  if defined(IMPLEMENT_THREAD_LOCAL_VIA_WIN_TLS) || defined(IMPLEMENT_THREAD_LOCAL_EXTERNALLY_VIA_PROC)
372 static Thread_Local_Variables *(*dll_scheme_external_get_thread_local_variables)(void);
373 #  endif
374 # endif
375 # if MZSCHEME_VERSION_MAJOR >= 600
376 static void (*dll_scheme_embedded_load)(intptr_t len, const char *s, int predefined);
377 static void (*dll_scheme_register_embedded_load)(intptr_t len, const char *s);
378 static void (*dll_scheme_set_config_path)(Scheme_Object *p);
379 # endif
380 
381 #if defined(DYNAMIC_MZSCHEME) /* not when defined(PROTO) */
382 
383 /* arrays are imported directly */
384 # define scheme_eof dll_scheme_eof
385 # define scheme_false dll_scheme_false
386 # define scheme_void dll_scheme_void
387 # define scheme_null dll_scheme_null
388 # define scheme_true dll_scheme_true
389 
390 /* pointers are GetProceAddress'ed as pointers to pointer */
391 #if !defined(USE_THREAD_LOCAL) && !defined(LINK_EXTENSIONS_BY_TABLE)
392 #  define scheme_current_thread (*dll_scheme_current_thread_ptr)
393 # endif
394 # define scheme_console_printf (*dll_scheme_console_printf_ptr)
395 # define scheme_console_output (*dll_scheme_console_output_ptr)
396 # define scheme_notify_multithread (*dll_scheme_notify_multithread_ptr)
397 
398 /* and functions in a usual way */
399 # define GC_malloc dll_GC_malloc
400 # define GC_malloc_atomic dll_GC_malloc_atomic
401 
402 # define scheme_add_global dll_scheme_add_global
403 # define scheme_add_global_symbol dll_scheme_add_global_symbol
404 # define scheme_apply dll_scheme_apply
405 # define scheme_basic_env dll_scheme_basic_env
406 # define scheme_builtin_value dll_scheme_builtin_value
407 # if MZSCHEME_VERSION_MAJOR >= 299
408 #  define scheme_byte_string_to_char_string dll_scheme_byte_string_to_char_string
409 #  define scheme_make_path dll_scheme_make_path
410 # endif
411 # define scheme_check_threads dll_scheme_check_threads
412 # define scheme_close_input_port dll_scheme_close_input_port
413 # define scheme_count_lines dll_scheme_count_lines
414 # define scheme_current_continuation_marks \
415     dll_scheme_current_continuation_marks
416 # define scheme_display dll_scheme_display
417 # define scheme_display_to_string dll_scheme_display_to_string
418 # define scheme_do_eval dll_scheme_do_eval
419 # define scheme_dont_gc_ptr dll_scheme_dont_gc_ptr
420 # define scheme_eq dll_scheme_eq
421 # define scheme_eval dll_scheme_eval
422 # define scheme_eval_string dll_scheme_eval_string
423 # define scheme_eval_string_all dll_scheme_eval_string_all
424 # define scheme_finish_primitive_module dll_scheme_finish_primitive_module
425 # if MZSCHEME_VERSION_MAJOR < 299
426 #  define scheme_format dll_scheme_format
427 # else
428 #  define scheme_format_utf8 dll_scheme_format_utf8
429 # endif
430 # define scheme_gc_ptr_ok dll_scheme_gc_ptr_ok
431 # if MZSCHEME_VERSION_MAJOR < 299
432 #  define scheme_get_sized_byte_string_output dll_scheme_get_sized_string_output
433 # else
434 #  define scheme_get_sized_byte_string_output \
435     dll_scheme_get_sized_byte_string_output
436 #  define scheme_get_param dll_scheme_get_param
437 # endif
438 # define scheme_intern_symbol dll_scheme_intern_symbol
439 # define scheme_lookup_global dll_scheme_lookup_global
440 # define scheme_make_closed_prim_w_arity dll_scheme_make_closed_prim_w_arity
441 # define scheme_make_integer_value dll_scheme_make_integer_value
442 # define scheme_make_pair dll_scheme_make_pair
443 # define scheme_make_prim_w_arity dll_scheme_make_prim_w_arity
444 # if MZSCHEME_VERSION_MAJOR < 299
445 #  define scheme_make_byte_string dll_scheme_make_string
446 #  define scheme_make_byte_string_output_port dll_scheme_make_string_output_port
447 # else
448 #  define scheme_make_byte_string dll_scheme_make_byte_string
449 #  define scheme_make_byte_string_output_port \
450     dll_scheme_make_byte_string_output_port
451 # endif
452 # define scheme_make_struct_instance dll_scheme_make_struct_instance
453 # define scheme_make_struct_names dll_scheme_make_struct_names
454 # define scheme_make_struct_type dll_scheme_make_struct_type
455 # define scheme_make_struct_values dll_scheme_make_struct_values
456 # define scheme_make_type dll_scheme_make_type
457 # define scheme_make_vector dll_scheme_make_vector
458 # define scheme_malloc_fail_ok dll_scheme_malloc_fail_ok
459 # define scheme_open_input_file dll_scheme_open_input_file
460 # define scheme_primitive_module dll_scheme_primitive_module
461 # define scheme_proper_list_length dll_scheme_proper_list_length
462 # define scheme_raise dll_scheme_raise
463 # define scheme_read dll_scheme_read
464 # define scheme_register_static dll_scheme_register_static
465 # define scheme_set_stack_base dll_scheme_set_stack_base
466 # define scheme_signal_error dll_scheme_signal_error
467 # define scheme_wrong_type dll_scheme_wrong_type
468 # if MZSCHEME_VERSION_MAJOR >= 299
469 #  define scheme_set_param dll_scheme_set_param
470 #  define scheme_current_config dll_scheme_current_config
471 #  define scheme_char_string_to_byte_string \
472     dll_scheme_char_string_to_byte_string
473 #  define scheme_char_string_to_path \
474     dll_scheme_char_string_to_path
475 #  define scheme_set_collects_path dll_scheme_set_collects_path
476 # endif
477 # define scheme_make_hash_table dll_scheme_make_hash_table
478 # define scheme_hash_set dll_scheme_hash_set
479 # define scheme_hash_get dll_scheme_hash_get
480 # define scheme_make_double dll_scheme_make_double
481 # define scheme_make_sized_byte_string dll_scheme_make_sized_byte_string
482 # define scheme_namespace_require dll_scheme_namespace_require
483 # define scheme_dynamic_wind dll_scheme_dynamic_wind
484 # ifdef MZ_PRECISE_GC
485 #  define GC_malloc_one_tagged dll_GC_malloc_one_tagged
486 #  define GC_register_traversers dll_GC_register_traversers
487 # endif
488 # if MZSCHEME_VERSION_MAJOR >= 400
489 #  ifdef TRAMPOLINED_MZVIM_STARTUP
490 #   define scheme_main_setup dll_scheme_main_setup
491 #   if defined(IMPLEMENT_THREAD_LOCAL_VIA_WIN_TLS) || MZSCHEME_VERSION_MAJOR >= 603
492 #    define scheme_register_tls_space dll_scheme_register_tls_space
493 #   endif
494 #  endif
495 #  define scheme_init_collection_paths dll_scheme_init_collection_paths
496 #  define scheme_malloc_immobile_box dll_scheme_malloc_immobile_box
497 #  define scheme_free_immobile_box dll_scheme_free_immobile_box
498 # endif
499 # if MZSCHEME_VERSION_MAJOR >= 600
500 #  define scheme_embedded_load dll_scheme_embedded_load
501 #  define scheme_register_embedded_load dll_scheme_register_embedded_load
502 #  define scheme_set_config_path dll_scheme_set_config_path
503 # endif
504 
505 # if MZSCHEME_VERSION_MAJOR >= 500
506 #  if defined(IMPLEMENT_THREAD_LOCAL_VIA_WIN_TLS) || defined(IMPLEMENT_THREAD_LOCAL_EXTERNALLY_VIA_PROC)
507 /* define as function for macro in schthread.h */
508 Thread_Local_Variables *
509 scheme_external_get_thread_local_variables(void)
510 {
511     return dll_scheme_external_get_thread_local_variables();
512 }
513 #  endif
514 # endif
515 
516 #endif
517 
518 typedef struct
519 {
520     char    *name;
521     void    **ptr;
522 } Thunk_Info;
523 
524 static Thunk_Info mzgc_imports[] = {
525     {"GC_malloc", (void **)&dll_GC_malloc},
526     {"GC_malloc_atomic", (void **)&dll_GC_malloc_atomic},
527     {NULL, NULL}};
528 
529 static Thunk_Info mzsch_imports[] = {
530     {"scheme_eof", (void **)&dll_scheme_eof},
531     {"scheme_false", (void **)&dll_scheme_false},
532     {"scheme_void", (void **)&dll_scheme_void},
533     {"scheme_null", (void **)&dll_scheme_null},
534     {"scheme_true", (void **)&dll_scheme_true},
535 #if !defined(USE_THREAD_LOCAL) && !defined(LINK_EXTENSIONS_BY_TABLE)
536     {"scheme_current_thread", (void **)&dll_scheme_current_thread_ptr},
537 #endif
538     {"scheme_console_printf", (void **)&dll_scheme_console_printf_ptr},
539     {"scheme_console_output", (void **)&dll_scheme_console_output_ptr},
540     {"scheme_notify_multithread",
541 	(void **)&dll_scheme_notify_multithread_ptr},
542     {"scheme_add_global", (void **)&dll_scheme_add_global},
543     {"scheme_add_global_symbol", (void **)&dll_scheme_add_global_symbol},
544     {"scheme_apply", (void **)&dll_scheme_apply},
545     {"scheme_basic_env", (void **)&dll_scheme_basic_env},
546 # if MZSCHEME_VERSION_MAJOR >= 299
547     {"scheme_byte_string_to_char_string", (void **)&dll_scheme_byte_string_to_char_string},
548     {"scheme_make_path", (void **)&dll_scheme_make_path},
549 # endif
550     {"scheme_builtin_value", (void **)&dll_scheme_builtin_value},
551     {"scheme_check_threads", (void **)&dll_scheme_check_threads},
552     {"scheme_close_input_port", (void **)&dll_scheme_close_input_port},
553     {"scheme_count_lines", (void **)&dll_scheme_count_lines},
554     {"scheme_current_continuation_marks",
555 	(void **)&dll_scheme_current_continuation_marks},
556     {"scheme_display", (void **)&dll_scheme_display},
557     {"scheme_display_to_string", (void **)&dll_scheme_display_to_string},
558     {"scheme_do_eval", (void **)&dll_scheme_do_eval},
559     {"scheme_dont_gc_ptr", (void **)&dll_scheme_dont_gc_ptr},
560     {"scheme_eq", (void **)&dll_scheme_eq},
561     {"scheme_eval", (void **)&dll_scheme_eval},
562     {"scheme_eval_string", (void **)&dll_scheme_eval_string},
563     {"scheme_eval_string_all", (void **)&dll_scheme_eval_string_all},
564     {"scheme_finish_primitive_module",
565 	(void **)&dll_scheme_finish_primitive_module},
566 # if MZSCHEME_VERSION_MAJOR < 299
567     {"scheme_format", (void **)&dll_scheme_format},
568 # else
569     {"scheme_format_utf8", (void **)&dll_scheme_format_utf8},
570     {"scheme_get_param", (void **)&dll_scheme_get_param},
571 #endif
572     {"scheme_gc_ptr_ok", (void **)&dll_scheme_gc_ptr_ok},
573 # if MZSCHEME_VERSION_MAJOR < 299
574     {"scheme_get_sized_string_output",
575 	(void **)&dll_scheme_get_sized_string_output},
576 # else
577     {"scheme_get_sized_byte_string_output",
578 	(void **)&dll_scheme_get_sized_byte_string_output},
579 #endif
580     {"scheme_intern_symbol", (void **)&dll_scheme_intern_symbol},
581     {"scheme_lookup_global", (void **)&dll_scheme_lookup_global},
582     {"scheme_make_closed_prim_w_arity",
583 	(void **)&dll_scheme_make_closed_prim_w_arity},
584     {"scheme_make_integer_value", (void **)&dll_scheme_make_integer_value},
585     {"scheme_make_pair", (void **)&dll_scheme_make_pair},
586     {"scheme_make_prim_w_arity", (void **)&dll_scheme_make_prim_w_arity},
587 # if MZSCHEME_VERSION_MAJOR < 299
588     {"scheme_make_string", (void **)&dll_scheme_make_string},
589     {"scheme_make_string_output_port",
590 	(void **)&dll_scheme_make_string_output_port},
591 # else
592     {"scheme_make_byte_string", (void **)&dll_scheme_make_byte_string},
593     {"scheme_make_byte_string_output_port",
594 	(void **)&dll_scheme_make_byte_string_output_port},
595 # endif
596     {"scheme_make_struct_instance",
597 	(void **)&dll_scheme_make_struct_instance},
598     {"scheme_make_struct_names", (void **)&dll_scheme_make_struct_names},
599     {"scheme_make_struct_type", (void **)&dll_scheme_make_struct_type},
600     {"scheme_make_struct_values", (void **)&dll_scheme_make_struct_values},
601     {"scheme_make_type", (void **)&dll_scheme_make_type},
602     {"scheme_make_vector", (void **)&dll_scheme_make_vector},
603     {"scheme_malloc_fail_ok", (void **)&dll_scheme_malloc_fail_ok},
604     {"scheme_open_input_file", (void **)&dll_scheme_open_input_file},
605     {"scheme_primitive_module", (void **)&dll_scheme_primitive_module},
606     {"scheme_proper_list_length", (void **)&dll_scheme_proper_list_length},
607     {"scheme_raise", (void **)&dll_scheme_raise},
608     {"scheme_read", (void **)&dll_scheme_read},
609     {"scheme_register_static", (void **)&dll_scheme_register_static},
610     {"scheme_set_stack_base", (void **)&dll_scheme_set_stack_base},
611     {"scheme_signal_error", (void **)&dll_scheme_signal_error},
612     {"scheme_wrong_type", (void **)&dll_scheme_wrong_type},
613 # if MZSCHEME_VERSION_MAJOR >= 299
614     {"scheme_set_param", (void **)&dll_scheme_set_param},
615     {"scheme_current_config", (void **)&dll_scheme_current_config},
616     {"scheme_char_string_to_byte_string",
617 	(void **)&dll_scheme_char_string_to_byte_string},
618     {"scheme_char_string_to_path", (void **)&dll_scheme_char_string_to_path},
619     {"scheme_set_collects_path", (void **)&dll_scheme_set_collects_path},
620 # endif
621     {"scheme_make_hash_table", (void **)&dll_scheme_make_hash_table},
622     {"scheme_hash_set", (void **)&dll_scheme_hash_set},
623     {"scheme_hash_get", (void **)&dll_scheme_hash_get},
624     {"scheme_make_double", (void **)&dll_scheme_make_double},
625     {"scheme_make_sized_byte_string", (void **)&dll_scheme_make_sized_byte_string},
626     {"scheme_namespace_require", (void **)&dll_scheme_namespace_require},
627     {"scheme_dynamic_wind", (void **)&dll_scheme_dynamic_wind},
628 # ifdef MZ_PRECISE_GC
629     {"GC_malloc_one_tagged", (void **)&dll_GC_malloc_one_tagged},
630     {"GC_register_traversers", (void **)&dll_GC_register_traversers},
631 # endif
632 # if MZSCHEME_VERSION_MAJOR >= 400
633 #  ifdef TRAMPOLINED_MZVIM_STARTUP
634     {"scheme_main_setup", (void **)&dll_scheme_main_setup},
635 #   if defined(IMPLEMENT_THREAD_LOCAL_VIA_WIN_TLS) || MZSCHEME_VERSION_MAJOR >= 603
636     {"scheme_register_tls_space", (void **)&dll_scheme_register_tls_space},
637 #   endif
638 #  endif
639     {"scheme_init_collection_paths", (void **)&dll_scheme_init_collection_paths},
640     {"scheme_malloc_immobile_box", (void **)&dll_scheme_malloc_immobile_box},
641     {"scheme_free_immobile_box", (void **)&dll_scheme_free_immobile_box},
642 # endif
643 # if MZSCHEME_VERSION_MAJOR >= 500
644 #  if defined(IMPLEMENT_THREAD_LOCAL_VIA_WIN_TLS) || defined(IMPLEMENT_THREAD_LOCAL_EXTERNALLY_VIA_PROC)
645     {"scheme_external_get_thread_local_variables", (void **)&dll_scheme_external_get_thread_local_variables},
646 #  endif
647 # endif
648 # if MZSCHEME_VERSION_MAJOR >= 600
649     {"scheme_embedded_load", (void **)&dll_scheme_embedded_load},
650     {"scheme_register_embedded_load", (void **)&dll_scheme_register_embedded_load},
651     {"scheme_set_config_path", (void **)&dll_scheme_set_config_path},
652 # endif
653     {NULL, NULL}};
654 
655 static HINSTANCE hMzGC = 0;
656 static HINSTANCE hMzSch = 0;
657 
658 static void dynamic_mzscheme_end(void);
659 static int mzscheme_runtime_link_init(char *sch_dll, char *gc_dll,
660 	int verbose);
661 
662     static int
663 mzscheme_runtime_link_init(char *sch_dll, char *gc_dll, int verbose)
664 {
665     Thunk_Info *thunk = NULL;
666 
667     if (hMzGC && hMzSch)
668 	return OK;
669     hMzSch = vimLoadLib(sch_dll);
670     hMzGC = vimLoadLib(gc_dll);
671 
672     if (!hMzGC)
673     {
674 	if (verbose)
675 	    semsg(_(e_loadlib), gc_dll);
676 	return FAIL;
677     }
678 
679     if (!hMzSch)
680     {
681 	if (verbose)
682 	    semsg(_(e_loadlib), sch_dll);
683 	return FAIL;
684     }
685 
686     for (thunk = mzsch_imports; thunk->name; thunk++)
687     {
688 	if ((*thunk->ptr =
689 		    (void *)GetProcAddress(hMzSch, thunk->name)) == NULL)
690 	{
691 	    FreeLibrary(hMzSch);
692 	    hMzSch = 0;
693 	    FreeLibrary(hMzGC);
694 	    hMzGC = 0;
695 	    if (verbose)
696 		semsg(_(e_loadfunc), thunk->name);
697 	    return FAIL;
698 	}
699     }
700     for (thunk = mzgc_imports; thunk->name; thunk++)
701     {
702 	if ((*thunk->ptr =
703 		    (void *)GetProcAddress(hMzGC, thunk->name)) == NULL)
704 	{
705 	    FreeLibrary(hMzSch);
706 	    hMzSch = 0;
707 	    FreeLibrary(hMzGC);
708 	    hMzGC = 0;
709 	    if (verbose)
710 		semsg(_(e_loadfunc), thunk->name);
711 	    return FAIL;
712 	}
713     }
714     return OK;
715 }
716 
717     int
718 mzscheme_enabled(int verbose)
719 {
720     return mzscheme_runtime_link_init(
721 	    (char *)p_mzschemedll, (char *)p_mzschemegcdll, verbose) == OK;
722 }
723 
724     static void
725 dynamic_mzscheme_end(void)
726 {
727     if (hMzSch)
728     {
729 	FreeLibrary(hMzSch);
730 	hMzSch = 0;
731     }
732     if (hMzGC)
733     {
734 	FreeLibrary(hMzGC);
735 	hMzGC = 0;
736     }
737 }
738 #endif /* DYNAMIC_MZSCHEME */
739 
740 #if MZSCHEME_VERSION_MAJOR < 299
741 # define GUARANTEED_STRING_ARG(proc, num) GUARANTEE_STRING(proc, num)
742 #else
743     static Scheme_Object *
744 guaranteed_byte_string_arg(char *proc, int num, int argc, Scheme_Object **argv)
745 {
746     if (SCHEME_BYTE_STRINGP(argv[num]))
747     {
748 	return argv[num];
749     }
750     else if (SCHEME_CHAR_STRINGP(argv[num]))
751     {
752 	Scheme_Object *tmp = NULL;
753 	MZ_GC_DECL_REG(2);
754 	MZ_GC_VAR_IN_REG(0, argv[num]);
755 	MZ_GC_VAR_IN_REG(1, tmp);
756 	MZ_GC_REG();
757 	tmp = scheme_char_string_to_byte_string(argv[num]);
758 	MZ_GC_UNREG();
759 	return tmp;
760     }
761     else
762 	scheme_wrong_type(proc, "string", num, argc, argv);
763     /* unreachable */
764     return scheme_void;
765 }
766 # define GUARANTEED_STRING_ARG(proc, num) guaranteed_byte_string_arg(proc, num, argc, argv)
767 #endif
768 
769 /* need to put it here for dynamic stuff to work */
770 #if defined(INCLUDE_MZSCHEME_BASE)
771 # include "mzscheme_base.c"
772 #endif
773 
774 /*
775  *========================================================================
776  *  1. MzScheme interpreter startup
777  *========================================================================
778  */
779 
780 static Scheme_Type mz_buffer_type;
781 static Scheme_Type mz_window_type;
782 
783 static int initialized = FALSE;
784 #ifdef DYNAMIC_MZSCHEME
785 static int disabled = FALSE;
786 #endif
787 static int load_base_module_failed = FALSE;
788 
789 /* global environment */
790 static Scheme_Env    *environment = NULL;
791 /* output/error handlers */
792 static Scheme_Object *curout = NULL;
793 static Scheme_Object *curerr = NULL;
794 /* exn:vim exception */
795 static Scheme_Object *exn_catching_apply = NULL;
796 static Scheme_Object *exn_p = NULL;
797 static Scheme_Object *exn_message = NULL;
798 static Scheme_Object *vim_exn = NULL; /* Vim Error exception */
799 
800 #if !defined(MZ_PRECISE_GC) || MZSCHEME_VERSION_MAJOR < 400
801 static void *stack_base = NULL;
802 #endif
803 
804 static long range_start;
805 static long range_end;
806 
807 /* MzScheme threads scheduling stuff */
808 static int mz_threads_allow = 0;
809 
810 #if defined(FEAT_GUI_W32)
811 static void CALLBACK timer_proc(HWND, UINT, UINT_PTR, DWORD);
812 static UINT timer_id = 0;
813 #elif defined(FEAT_GUI_GTK)
814 static gboolean timer_proc(gpointer);
815 static guint timer_id = 0;
816 #elif defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_ATHENA)
817 static void timer_proc(XtPointer, XtIntervalId *);
818 static XtIntervalId timer_id = (XtIntervalId)0;
819 #elif defined(FEAT_GUI_MAC)
820 pascal void timer_proc(EventLoopTimerRef, void *);
821 static EventLoopTimerRef timer_id = NULL;
822 static EventLoopTimerUPP timerUPP;
823 #endif
824 
825 #ifndef FEAT_GUI_W32 /* Win32 console and Unix */
826     void
827 mzvim_check_threads(void)
828 {
829     /* Last time MzScheme threads were scheduled */
830     static time_t mz_last_time = 0;
831 
832     if (mz_threads_allow && p_mzq > 0)
833     {
834 	time_t now = time(NULL);
835 
836 	if ((now - mz_last_time) * 1000 > p_mzq)
837 	{
838 	    mz_last_time = now;
839 	    scheme_check_threads();
840 	}
841     }
842 }
843 #endif
844 
845 #if defined(MZSCHEME_GUI_THREADS) || defined(PROTO)
846 static void setup_timer(void);
847 static void remove_timer(void);
848 
849 /* timers are presented in GUI only */
850 # if defined(FEAT_GUI_W32)
851     static void CALLBACK
852 timer_proc(HWND hwnd UNUSED, UINT uMsg UNUSED, UINT_PTR idEvent UNUSED, DWORD dwTime UNUSED)
853 # elif defined(FEAT_GUI_GTK)
854     static gboolean
855 timer_proc(gpointer data UNUSED)
856 # elif defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_ATHENA)
857     static void
858 timer_proc(XtPointer timed_out UNUSED, XtIntervalId *interval_id UNUSED)
859 # elif defined(FEAT_GUI_MAC)
860     pascal void
861 timer_proc(EventLoopTimerRef theTimer UNUSED, void *userData UNUSED)
862 # endif
863 {
864     scheme_check_threads();
865 # if defined(FEAT_GUI_GTK)
866     return TRUE; /* continue receiving notifications */
867 # elif defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_ATHENA)
868     /* renew timeout */
869     if (mz_threads_allow && p_mzq > 0)
870 	timer_id = XtAppAddTimeOut(app_context, p_mzq,
871 		timer_proc, NULL);
872 # endif
873 }
874 
875     static void
876 setup_timer(void)
877 {
878 # if defined(FEAT_GUI_W32)
879     timer_id = SetTimer(NULL, 0, p_mzq, timer_proc);
880 # elif defined(FEAT_GUI_GTK)
881     timer_id = g_timeout_add((guint)p_mzq, (GSourceFunc)timer_proc, NULL);
882 # elif defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_ATHENA)
883     timer_id = XtAppAddTimeOut(app_context, p_mzq, timer_proc, NULL);
884 # elif defined(FEAT_GUI_MAC)
885     timerUPP = NewEventLoopTimerUPP(timer_proc);
886     InstallEventLoopTimer(GetMainEventLoop(), p_mzq * kEventDurationMillisecond,
887 		p_mzq * kEventDurationMillisecond, timerUPP, NULL, &timer_id);
888 # endif
889 }
890 
891     static void
892 remove_timer(void)
893 {
894 # if defined(FEAT_GUI_W32)
895     KillTimer(NULL, timer_id);
896 # elif defined(FEAT_GUI_GTK)
897     g_source_remove(timer_id);
898 # elif defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_ATHENA)
899     XtRemoveTimeOut(timer_id);
900 # elif defined(FEAT_GUI_MAC)
901     RemoveEventLoopTimer(timer_id);
902     DisposeEventLoopTimerUPP(timerUPP);
903 # endif
904     timer_id = 0;
905 }
906 
907     void
908 mzvim_reset_timer(void)
909 {
910     if (timer_id != 0)
911 	remove_timer();
912     if (mz_threads_allow && p_mzq > 0 && gui.in_use)
913 	setup_timer();
914 }
915 
916 #endif /* MZSCHEME_GUI_THREADS */
917 
918     static void
919 notify_multithread(int on)
920 {
921     mz_threads_allow = on;
922 #ifdef MZSCHEME_GUI_THREADS
923     if (on && timer_id == 0 && p_mzq > 0 && gui.in_use)
924 	setup_timer();
925     if (!on && timer_id != 0)
926 	remove_timer();
927 #endif
928 }
929 
930     void
931 mzscheme_end(void)
932 {
933     /* We can not unload the DLL.  Racket's thread might be still alive. */
934 #if 0
935 #ifdef DYNAMIC_MZSCHEME
936     dynamic_mzscheme_end();
937 #endif
938 #endif
939 }
940 
941 #if HAVE_TLS_SPACE
942 # if defined(_MSC_VER)
943 static __declspec(thread) void *tls_space;
944 extern intptr_t _tls_index;
945 # elif defined(__MINGW32__)
946 static __thread void *tls_space;
947 extern intptr_t _tls_index;
948 # else
949 static THREAD_LOCAL void *tls_space;
950 static intptr_t _tls_index = 0;
951 # endif
952 #endif
953 
954 /*
955  * mzscheme_main() is called early in main().
956  * We may call scheme_main_setup() which calls mzscheme_env_main() which then
957  * trampolines into vim_main2(), which never returns.
958  */
959     int
960 mzscheme_main(void)
961 {
962     int	    argc = 0;
963     char    *argv = NULL;
964 
965 #ifdef DYNAMIC_MZSCHEME
966     /*
967      * Racket requires trampolined startup.  We can not load it later.
968      * If dynamic dll loading is failed, disable it.
969      */
970     if (!mzscheme_enabled(FALSE))
971     {
972 	disabled = TRUE;
973 	return vim_main2();
974     }
975 #endif
976 #ifdef HAVE_TLS_SPACE
977     scheme_register_tls_space(&tls_space, _tls_index);
978 #endif
979 #ifdef TRAMPOLINED_MZVIM_STARTUP
980     return scheme_main_setup(TRUE, mzscheme_env_main, argc, &argv);
981 #else
982     return mzscheme_env_main(NULL, argc, &argv);
983 #endif
984 }
985 
986     static int
987 mzscheme_env_main(Scheme_Env *env, int argc UNUSED, char **argv UNUSED)
988 {
989 #ifdef TRAMPOLINED_MZVIM_STARTUP
990     /* Scheme has created the environment for us */
991     environment = env;
992 #else
993 # ifdef MZ_PRECISE_GC
994     Scheme_Object   *dummy = NULL;
995     MZ_GC_DECL_REG(1);
996     MZ_GC_VAR_IN_REG(0, dummy);
997 
998     stack_base = &__gc_var_stack__;
999 # else
1000     int dummy = 0;
1001     stack_base = (void *)&dummy;
1002 # endif
1003 #endif
1004 
1005     vim_main2();
1006     /* not reached, vim_main2() will loop until exit() */
1007 
1008     return 0;
1009 }
1010 
1011     static Scheme_Object*
1012 load_base_module(void *data)
1013 {
1014     scheme_namespace_require(scheme_intern_symbol((char *)data));
1015     return scheme_null;
1016 }
1017 
1018     static Scheme_Object *
1019 load_base_module_on_error(void *data UNUSED)
1020 {
1021     load_base_module_failed = TRUE;
1022     return scheme_null;
1023 }
1024 
1025     static int
1026 startup_mzscheme(void)
1027 {
1028 #ifndef TRAMPOLINED_MZVIM_STARTUP
1029     scheme_set_stack_base(stack_base, 1);
1030 #endif
1031 
1032 #ifndef TRAMPOLINED_MZVIM_STARTUP
1033     /* in newer versions of precise GC the initial env has been created */
1034     environment = scheme_basic_env();
1035 #endif
1036 
1037     MZ_REGISTER_STATIC(environment);
1038     MZ_REGISTER_STATIC(curout);
1039     MZ_REGISTER_STATIC(curerr);
1040     MZ_REGISTER_STATIC(exn_catching_apply);
1041     MZ_REGISTER_STATIC(exn_p);
1042     MZ_REGISTER_STATIC(exn_message);
1043     MZ_REGISTER_STATIC(vim_exn);
1044 
1045     MZ_GC_CHECK();
1046 
1047 #ifdef INCLUDE_MZSCHEME_BASE
1048     /* invoke function from generated and included mzscheme_base.c */
1049     declare_modules(environment);
1050 #endif
1051 
1052     /* setup 'current-library-collection-paths' parameter */
1053 # if MZSCHEME_VERSION_MAJOR >= 299
1054     {
1055 	Scheme_Object *coll_path = NULL;
1056 	int mustfree = FALSE;
1057 	char_u *s;
1058 
1059 	MZ_GC_DECL_REG(1);
1060 	MZ_GC_VAR_IN_REG(0, coll_path);
1061 	MZ_GC_REG();
1062 	/* workaround for dynamic loading on windows */
1063 	s = vim_getenv((char_u *)"PLTCOLLECTS", &mustfree);
1064 	if (s != NULL)
1065 	{
1066 	    coll_path = scheme_make_path((char *)s);
1067 	    MZ_GC_CHECK();
1068 	    if (mustfree)
1069 		vim_free(s);
1070 	}
1071 #  ifdef MZSCHEME_COLLECTS
1072 	if (coll_path == NULL)
1073 	{
1074 	    coll_path = scheme_make_path(MZSCHEME_COLLECTS);
1075 	    MZ_GC_CHECK();
1076 	}
1077 #  endif
1078 	if (coll_path != NULL)
1079 	{
1080 	    scheme_set_collects_path(coll_path);
1081 	    MZ_GC_CHECK();
1082 	}
1083 	MZ_GC_UNREG();
1084     }
1085 # else
1086 #  ifdef MZSCHEME_COLLECTS
1087     {
1088 	Scheme_Object	*coll_string = NULL;
1089 	Scheme_Object	*coll_pair = NULL;
1090 	Scheme_Config	*config = NULL;
1091 
1092 	MZ_GC_DECL_REG(3);
1093 	MZ_GC_VAR_IN_REG(0, coll_string);
1094 	MZ_GC_VAR_IN_REG(1, coll_pair);
1095 	MZ_GC_VAR_IN_REG(2, config);
1096 	MZ_GC_REG();
1097 	coll_string = scheme_make_byte_string(MZSCHEME_COLLECTS);
1098 	MZ_GC_CHECK();
1099 	coll_pair = scheme_make_pair(coll_string, scheme_null);
1100 	MZ_GC_CHECK();
1101 	config = scheme_current_config();
1102 	MZ_GC_CHECK();
1103 	scheme_set_param(config, MZCONFIG_COLLECTION_PATHS, coll_pair);
1104 	MZ_GC_CHECK();
1105 	MZ_GC_UNREG();
1106     }
1107 # endif
1108 #endif
1109 
1110 # if MZSCHEME_VERSION_MAJOR >= 600
1111     {
1112 	Scheme_Object *config_path = NULL;
1113 	int mustfree = FALSE;
1114 	char_u *s;
1115 
1116 	MZ_GC_DECL_REG(1);
1117 	MZ_GC_VAR_IN_REG(0, config_path);
1118 	MZ_GC_REG();
1119 	/* workaround for dynamic loading on windows */
1120 	s = vim_getenv((char_u *)"PLTCONFIGDIR", &mustfree);
1121 	if (s != NULL)
1122 	{
1123 	    config_path = scheme_make_path((char *)s);
1124 	    MZ_GC_CHECK();
1125 	    if (mustfree)
1126 		vim_free(s);
1127 	}
1128 #ifdef MZSCHEME_CONFIGDIR
1129 	if (config_path == NULL)
1130 	{
1131 	    config_path = scheme_make_path(MZSCHEME_CONFIGDIR);
1132 	    MZ_GC_CHECK();
1133 	}
1134 #endif
1135 	if (config_path != NULL)
1136 	{
1137 	    scheme_set_config_path(config_path);
1138 	    MZ_GC_CHECK();
1139 	}
1140 	MZ_GC_UNREG();
1141     }
1142 # endif
1143 
1144 #if MZSCHEME_VERSION_MAJOR >= 400
1145     scheme_init_collection_paths(environment, scheme_null);
1146 #endif
1147 
1148     /*
1149      * versions 4.x do not provide Scheme bindings by default
1150      * we need to add them explicitly
1151      */
1152     {
1153 	/* use error handler to avoid abort */
1154 	scheme_dynamic_wind(NULL, load_base_module, NULL,
1155 				    load_base_module_on_error, "racket/base");
1156 	if (load_base_module_failed)
1157 	{
1158 	    load_base_module_failed = FALSE;
1159 	    scheme_dynamic_wind(NULL, load_base_module, NULL,
1160 				    load_base_module_on_error, "scheme/base");
1161 	    if (load_base_module_failed)
1162 		return -1;
1163 	}
1164     }
1165 
1166     register_vim_exn();
1167     /* use new environment to initialise exception handling */
1168     init_exn_catching_apply();
1169 
1170     /* redirect output */
1171     scheme_console_output = do_output;
1172     scheme_console_printf = do_printf;
1173 
1174 #ifdef HAVE_SANDBOX
1175     {
1176 	Scheme_Object	*make_security_guard = NULL;
1177 	MZ_GC_DECL_REG(1);
1178 	MZ_GC_VAR_IN_REG(0, make_security_guard);
1179 	MZ_GC_REG();
1180 
1181 #if MZSCHEME_VERSION_MAJOR < 400
1182 	{
1183 	    Scheme_Object	*make_security_guard_symbol = NULL;
1184 	    MZ_GC_DECL_REG(1);
1185 	    MZ_GC_VAR_IN_REG(0, make_security_guard_symbol);
1186 	    MZ_GC_REG();
1187 	    make_security_guard_symbol = scheme_intern_symbol("make-security-guard");
1188 	    MZ_GC_CHECK();
1189 	    make_security_guard = scheme_lookup_global(
1190 		    make_security_guard_symbol, environment);
1191 	    MZ_GC_UNREG();
1192 	}
1193 #else
1194 	make_security_guard = scheme_builtin_value("make-security-guard");
1195 	MZ_GC_CHECK();
1196 #endif
1197 
1198 	/* setup sandbox guards */
1199 	if (make_security_guard != NULL)
1200 	{
1201 	    Scheme_Object   *args[3] = {NULL, NULL, NULL};
1202 	    Scheme_Object   *guard = NULL;
1203 	    Scheme_Config   *config = NULL;
1204 	    MZ_GC_DECL_REG(5);
1205 	    MZ_GC_ARRAY_VAR_IN_REG(0, args, 3);
1206 	    MZ_GC_VAR_IN_REG(3, guard);
1207 	    MZ_GC_VAR_IN_REG(4, config);
1208 	    MZ_GC_REG();
1209 	    config = scheme_current_config();
1210 	    MZ_GC_CHECK();
1211 	    args[0] = scheme_get_param(config, MZCONFIG_SECURITY_GUARD);
1212 	    MZ_GC_CHECK();
1213 	    args[1] = scheme_make_prim_w_arity(sandbox_file_guard,
1214 		    "sandbox-file-guard", 3, 3);
1215 	    args[2] = scheme_make_prim_w_arity(sandbox_network_guard,
1216 		    "sandbox-network-guard", 4, 4);
1217 	    guard = scheme_apply(make_security_guard, 3, args);
1218 	    MZ_GC_CHECK();
1219 	    scheme_set_param(config, MZCONFIG_SECURITY_GUARD, guard);
1220 	    MZ_GC_CHECK();
1221 	    MZ_GC_UNREG();
1222 	}
1223 	MZ_GC_UNREG();
1224     }
1225 #endif
1226     /* Create buffer and window types for use in Scheme code */
1227     mz_buffer_type = scheme_make_type("<vim-buffer>");
1228     MZ_GC_CHECK();
1229     mz_window_type = scheme_make_type("<vim-window>");
1230     MZ_GC_CHECK();
1231 #ifdef MZ_PRECISE_GC
1232     GC_register_traversers(mz_buffer_type,
1233 	    buffer_size_proc, buffer_mark_proc, buffer_fixup_proc,
1234 	    TRUE, TRUE);
1235     GC_register_traversers(mz_window_type,
1236 	    window_size_proc, window_mark_proc, window_fixup_proc,
1237 	    TRUE, TRUE);
1238 #endif
1239 
1240     make_modules();
1241 
1242     /*
1243      * setup callback to receive notifications
1244      * whether thread scheduling is (or not) required
1245      */
1246     scheme_notify_multithread = notify_multithread;
1247 
1248     return 0;
1249 }
1250 
1251 /*
1252  * This routine is called for each new invocation of MzScheme
1253  * to make sure things are properly initialized.
1254  */
1255     static int
1256 mzscheme_init(void)
1257 {
1258     if (!initialized)
1259     {
1260 #ifdef DYNAMIC_MZSCHEME
1261 	if (disabled || !mzscheme_enabled(TRUE))
1262 	{
1263 	    emsg(_("E815: Sorry, this command is disabled, the MzScheme libraries could not be loaded."));
1264 	    return -1;
1265 	}
1266 #endif
1267 	if (load_base_module_failed || startup_mzscheme())
1268 	{
1269 	    emsg(_("E895: Sorry, this command is disabled, the MzScheme's racket/base module could not be loaded."));
1270 	    return -1;
1271 	}
1272 	initialized = TRUE;
1273     }
1274     {
1275 	Scheme_Config	*config = NULL;
1276 	MZ_GC_DECL_REG(1);
1277 	MZ_GC_VAR_IN_REG(0, config);
1278 	MZ_GC_REG();
1279 	config = scheme_current_config();
1280 	MZ_GC_CHECK();
1281 	/* recreate ports each call effectively clearing these ones */
1282 	curout = scheme_make_byte_string_output_port();
1283 	MZ_GC_CHECK();
1284 	curerr = scheme_make_byte_string_output_port();
1285 	MZ_GC_CHECK();
1286 	scheme_set_param(config, MZCONFIG_OUTPUT_PORT, curout);
1287 	MZ_GC_CHECK();
1288 	scheme_set_param(config, MZCONFIG_ERROR_PORT, curerr);
1289 	MZ_GC_CHECK();
1290 	MZ_GC_UNREG();
1291     }
1292 
1293     return 0;
1294 }
1295 
1296 /*
1297  *========================================================================
1298  *  2.  External Interface
1299  *========================================================================
1300  */
1301 
1302 /*
1303  * Evaluate command with exception handling
1304  */
1305     static int
1306 eval_with_exn_handling(void *data, Scheme_Closed_Prim *what, Scheme_Object **ret)
1307 {
1308     Scheme_Object   *value = NULL;
1309     Scheme_Object   *exn = NULL;
1310     Scheme_Object   *prim = NULL;
1311 
1312     MZ_GC_DECL_REG(3);
1313     MZ_GC_VAR_IN_REG(0, value);
1314     MZ_GC_VAR_IN_REG(1, exn);
1315     MZ_GC_VAR_IN_REG(2, prim);
1316     MZ_GC_REG();
1317 
1318     prim = scheme_make_closed_prim_w_arity(what, data, "mzvim", 0, 0);
1319     MZ_GC_CHECK();
1320     value = _apply_thunk_catch_exceptions(prim, &exn);
1321     MZ_GC_CHECK();
1322 
1323     if (!value)
1324     {
1325 	value = extract_exn_message(exn);
1326 	/* Got an exn? */
1327 	if (value)
1328 	{
1329 	    scheme_display(value, curerr);   /*  Send to stderr-vim */
1330 	    MZ_GC_CHECK();
1331 	    do_flush();
1332 	}
1333 	MZ_GC_UNREG();
1334 	/* `raise' was called on some arbitrary value */
1335 	return FAIL;
1336     }
1337 
1338     if (ret != NULL)	/* if pointer to retval supported give it up */
1339 	*ret = value;
1340     /* Print any result, as long as it's not a void */
1341     else if (!SCHEME_VOIDP(value))
1342     {
1343 	scheme_display(value, curout);  /* Send to stdout-vim */
1344 	MZ_GC_CHECK();
1345     }
1346 
1347     do_flush();
1348     MZ_GC_UNREG();
1349     return OK;
1350 }
1351 
1352 /* :mzscheme */
1353     static int
1354 do_mzscheme_command(exarg_T *eap, void *data, Scheme_Closed_Prim *what)
1355 {
1356     if (mzscheme_init())
1357 	return FAIL;
1358 
1359     range_start = eap->line1;
1360     range_end = eap->line2;
1361 
1362     return eval_with_exn_handling(data, what, NULL);
1363 }
1364 
1365 /*
1366  * Routine called by VIM when deleting a buffer
1367  */
1368     void
1369 mzscheme_buffer_free(buf_T *buf)
1370 {
1371     if (buf->b_mzscheme_ref)
1372     {
1373 	vim_mz_buffer *bp = NULL;
1374 	MZ_GC_DECL_REG(1);
1375 	MZ_GC_VAR_IN_REG(0, bp);
1376 	MZ_GC_REG();
1377 
1378 	bp = BUFFER_REF(buf);
1379 	bp->buf = INVALID_BUFFER_VALUE;
1380 #ifndef MZ_PRECISE_GC
1381 	scheme_gc_ptr_ok(bp);
1382 #else
1383 	scheme_free_immobile_box(buf->b_mzscheme_ref);
1384 #endif
1385 	buf->b_mzscheme_ref = NULL;
1386 	MZ_GC_CHECK();
1387 	MZ_GC_UNREG();
1388     }
1389 }
1390 
1391 /*
1392  * Routine called by VIM when deleting a Window
1393  */
1394     void
1395 mzscheme_window_free(win_T *win)
1396 {
1397     if (win->w_mzscheme_ref)
1398     {
1399 	vim_mz_window *wp = NULL;
1400 	MZ_GC_DECL_REG(1);
1401 	MZ_GC_VAR_IN_REG(0, wp);
1402 	MZ_GC_REG();
1403 	wp = WINDOW_REF(win);
1404 	wp->win = INVALID_WINDOW_VALUE;
1405 #ifndef MZ_PRECISE_GC
1406 	scheme_gc_ptr_ok(wp);
1407 #else
1408 	scheme_free_immobile_box(win->w_mzscheme_ref);
1409 #endif
1410 	win->w_mzscheme_ref = NULL;
1411 	MZ_GC_CHECK();
1412 	MZ_GC_UNREG();
1413     }
1414 }
1415 
1416 /*
1417  * ":mzscheme" (or ":mz")
1418  */
1419     void
1420 ex_mzscheme(exarg_T *eap)
1421 {
1422     char_u	*script;
1423 
1424     script = script_get(eap, eap->arg);
1425     if (!eap->skip)
1426     {
1427 	if (script == NULL)
1428 	    do_mzscheme_command(eap, eap->arg, do_eval);
1429 	else
1430 	{
1431 	    do_mzscheme_command(eap, script, do_eval);
1432 	    vim_free(script);
1433 	}
1434     }
1435 }
1436 
1437     static Scheme_Object *
1438 do_load(void *data, int noargc UNUSED, Scheme_Object **noargv UNUSED)
1439 {
1440     Scheme_Object   *expr = NULL;
1441     Scheme_Object   *result = NULL;
1442     char	    *file = NULL;
1443     Port_Info	    *pinfo = (Port_Info *)data;
1444 
1445     MZ_GC_DECL_REG(3);
1446     MZ_GC_VAR_IN_REG(0, expr);
1447     MZ_GC_VAR_IN_REG(1, result);
1448     MZ_GC_VAR_IN_REG(2, file);
1449     MZ_GC_REG();
1450 
1451     file = (char *)scheme_malloc_fail_ok(scheme_malloc_atomic, MAXPATHL + 1);
1452     MZ_GC_CHECK();
1453 
1454     /* make Vim expansion */
1455     expand_env((char_u *)pinfo->name, (char_u *)file, MAXPATHL);
1456     pinfo->port = scheme_open_input_file(file, "mzfile");
1457     MZ_GC_CHECK();
1458     scheme_count_lines(pinfo->port);  /* to get accurate read error location*/
1459     MZ_GC_CHECK();
1460 
1461     /* Like REPL but print only last result */
1462     while (!SCHEME_EOFP(expr = scheme_read(pinfo->port)))
1463     {
1464 	result = scheme_eval(expr, environment);
1465 	MZ_GC_CHECK();
1466     }
1467 
1468     /* errors will be caught in do_mzscheme_command and ex_mzfile */
1469     scheme_close_input_port(pinfo->port);
1470     MZ_GC_CHECK();
1471     pinfo->port = NULL;
1472     MZ_GC_UNREG();
1473     return result;
1474 }
1475 
1476 /* :mzfile */
1477     void
1478 ex_mzfile(exarg_T *eap)
1479 {
1480     Port_Info	pinfo = {NULL, NULL};
1481 
1482     MZ_GC_DECL_REG(1);
1483     MZ_GC_VAR_IN_REG(0, pinfo.port);
1484     MZ_GC_REG();
1485 
1486     pinfo.name = (char *)eap->arg;
1487     if (do_mzscheme_command(eap, &pinfo, do_load) != OK
1488 	    && pinfo.port != NULL)	/* looks like port was not closed */
1489     {
1490 	scheme_close_input_port(pinfo.port);
1491 	MZ_GC_CHECK();
1492     }
1493     MZ_GC_UNREG();
1494 }
1495 
1496 
1497 /*
1498  *========================================================================
1499  * Exception handling code -- cribbed form the MzScheme sources and
1500  * Matthew Flatt's "Inside PLT MzScheme" document.
1501  *========================================================================
1502  */
1503     static void
1504 init_exn_catching_apply(void)
1505 {
1506     if (!exn_catching_apply)
1507     {
1508 	char *e =
1509 	    "(lambda (thunk) "
1510 		"(with-handlers ([void (lambda (exn) (cons #f exn))]) "
1511 		"(cons #t (thunk))))";
1512 
1513 	exn_catching_apply = scheme_eval_string(e, environment);
1514 	MZ_GC_CHECK();
1515 	exn_p = scheme_builtin_value("exn?");
1516 	MZ_GC_CHECK();
1517 	exn_message = scheme_builtin_value("exn-message");
1518 	MZ_GC_CHECK();
1519     }
1520 }
1521 
1522 /*
1523  * This function applies a thunk, returning the Scheme value if there's
1524  * no exception, otherwise returning NULL and setting *exn to the raised
1525  * value (usually an exn structure).
1526  */
1527     static Scheme_Object *
1528 _apply_thunk_catch_exceptions(Scheme_Object *f, Scheme_Object **exn)
1529 {
1530     Scheme_Object *v;
1531 
1532     v = _scheme_apply(exn_catching_apply, 1, &f);
1533     /* v is a pair: (cons #t value) or (cons #f exn) */
1534 
1535     if (SCHEME_TRUEP(SCHEME_CAR(v)))
1536 	return SCHEME_CDR(v);
1537     else
1538     {
1539 	*exn = SCHEME_CDR(v);
1540 	return NULL;
1541     }
1542 }
1543 
1544     static Scheme_Object *
1545 extract_exn_message(Scheme_Object *v)
1546 {
1547     if (SCHEME_TRUEP(_scheme_apply(exn_p, 1, &v)))
1548 	return _scheme_apply(exn_message, 1, &v);
1549     else
1550 	return NULL; /* Not an exn structure */
1551 }
1552 
1553     static Scheme_Object *
1554 do_eval(void *s, int noargc UNUSED, Scheme_Object **noargv UNUSED)
1555 {
1556     return scheme_eval_string_all((char *)s, environment, TRUE);
1557 }
1558 
1559 /*
1560  *========================================================================
1561  *  3.  MzScheme I/O Handlers
1562  *========================================================================
1563  */
1564     static void
1565 do_intrnl_output(char *mesg, int error)
1566 {
1567     char *p, *prev;
1568 
1569     prev = mesg;
1570     p = strchr(prev, '\n');
1571     while (p)
1572     {
1573 	*p = '\0';
1574 	if (error)
1575 	    emsg(prev);
1576 	else
1577 	    msg(prev);
1578 	prev = p + 1;
1579 	p = strchr(prev, '\n');
1580     }
1581 
1582     if (error)
1583 	emsg(prev);
1584     else
1585 	msg(prev);
1586 }
1587 
1588     static void
1589 do_output(char *mesg, OUTPUT_LEN_TYPE len UNUSED)
1590 {
1591     /* TODO: use len, the string may not be NUL terminated */
1592     do_intrnl_output(mesg, 0);
1593 }
1594 
1595     static void
1596 do_err_output(char *mesg)
1597 {
1598     do_intrnl_output(mesg, 1);
1599 }
1600 
1601     static void
1602 do_printf(char *format, ...)
1603 {
1604     do_intrnl_output(format, 1);
1605 }
1606 
1607     static void
1608 do_flush(void)
1609 {
1610     char *buff;
1611     OUTPUT_LEN_TYPE length;
1612 
1613     buff = scheme_get_sized_byte_string_output(curerr, &length);
1614     MZ_GC_CHECK();
1615     if (length)
1616     {
1617 	do_err_output(buff);
1618 	return;
1619     }
1620 
1621     buff = scheme_get_sized_byte_string_output(curout, &length);
1622     MZ_GC_CHECK();
1623     if (length)
1624 	do_output(buff, length);
1625 }
1626 
1627 /*
1628  *========================================================================
1629  *  4. Implementation of the Vim Features for MzScheme
1630  *========================================================================
1631  */
1632 
1633 /* (command {command-string}) */
1634     static Scheme_Object *
1635 vim_command(void *data, int argc, Scheme_Object **argv)
1636 {
1637     Vim_Prim	*prim = (Vim_Prim *)data;
1638     Scheme_Object *cmd = NULL;
1639     MZ_GC_DECL_REG(1);
1640     MZ_GC_VAR_IN_REG(0, cmd);
1641     MZ_GC_REG();
1642     cmd = GUARANTEED_STRING_ARG(prim->name, 0);
1643 
1644     /* may be use do_cmdline_cmd? */
1645     do_cmdline(BYTE_STRING_VALUE(cmd), NULL, NULL, DOCMD_NOWAIT|DOCMD_VERBOSE);
1646     update_screen(VALID);
1647 
1648     MZ_GC_UNREG();
1649     raise_if_error();
1650     return scheme_void;
1651 }
1652 
1653 /* (eval {expr-string}) */
1654     static Scheme_Object *
1655 vim_eval(void *data UNUSED, int argc UNUSED, Scheme_Object **argv UNUSED)
1656 {
1657 #ifdef FEAT_EVAL
1658     Vim_Prim		*prim = (Vim_Prim *)data;
1659     Scheme_Object	*result = NULL;
1660     typval_T		*vim_result;
1661     Scheme_Object *expr = NULL;
1662     MZ_GC_DECL_REG(2);
1663     MZ_GC_VAR_IN_REG(0, result);
1664     MZ_GC_VAR_IN_REG(1, expr);
1665     MZ_GC_REG();
1666     expr = GUARANTEED_STRING_ARG(prim->name, 0);
1667 
1668     vim_result = eval_expr(BYTE_STRING_VALUE(expr), NULL);
1669 
1670     if (vim_result == NULL)
1671 	raise_vim_exn(_("invalid expression"));
1672 
1673     result = vim_to_mzscheme(vim_result);
1674     MZ_GC_CHECK();
1675     free_tv(vim_result);
1676 
1677     MZ_GC_UNREG();
1678     return result;
1679 #else
1680     raise_vim_exn(_("expressions disabled at compile time"));
1681     /* unreachable */
1682     return scheme_false;
1683 #endif
1684 }
1685 
1686 /* (range-start) */
1687     static Scheme_Object *
1688 get_range_start(void *data UNUSED, int argc UNUSED, Scheme_Object **argv UNUSED)
1689 {
1690     return scheme_make_integer(range_start);
1691 }
1692 
1693 /* (range-end) */
1694     static Scheme_Object *
1695 get_range_end(void *data UNUSED, int argc UNUSED, Scheme_Object **argv UNUSED)
1696 {
1697     return scheme_make_integer(range_end);
1698 }
1699 
1700 /* (beep) */
1701     static Scheme_Object *
1702 mzscheme_beep(void *data UNUSED, int argc UNUSED, Scheme_Object **argv UNUSED)
1703 {
1704     vim_beep(BO_LANG);
1705     return scheme_void;
1706 }
1707 
1708 static Scheme_Object *M_global = NULL;
1709 
1710 /* (get-option {option-name}) [buffer/window] */
1711     static Scheme_Object *
1712 get_option(void *data, int argc, Scheme_Object **argv)
1713 {
1714     Vim_Prim	    *prim = (Vim_Prim *)data;
1715     long	    value;
1716     char	    *strval;
1717     int		    rc;
1718     Scheme_Object   *rval = NULL;
1719     Scheme_Object   *name = NULL;
1720     int		    opt_flags = 0;
1721     buf_T	    *save_curb = curbuf;
1722     win_T	    *save_curw = curwin;
1723 
1724     MZ_GC_DECL_REG(2);
1725     MZ_GC_VAR_IN_REG(0, rval);
1726     MZ_GC_VAR_IN_REG(1, name);
1727     MZ_GC_REG();
1728 
1729     name = GUARANTEED_STRING_ARG(prim->name, 0);
1730 
1731     if (argc > 1)
1732     {
1733 	if (M_global == NULL)
1734 	{
1735 	    MZ_REGISTER_STATIC(M_global);
1736 	    M_global = scheme_intern_symbol("global");
1737 	    MZ_GC_CHECK();
1738 	}
1739 
1740 	if (argv[1] == M_global)
1741 	    opt_flags = OPT_GLOBAL;
1742 	else if (SCHEME_VIMBUFFERP(argv[1]))
1743 	{
1744 	    curbuf = get_valid_buffer(argv[1]);
1745 	    opt_flags = OPT_LOCAL;
1746 	}
1747 	else if (SCHEME_VIMWINDOWP(argv[1]))
1748 	{
1749 	    win_T *win = get_valid_window(argv[1]);
1750 
1751 	    curwin = win;
1752 	    curbuf = win->w_buffer;
1753 	    opt_flags = OPT_LOCAL;
1754 	}
1755 	else
1756 	    scheme_wrong_type(prim->name, "vim-buffer/window", 1, argc, argv);
1757     }
1758 
1759     rc = get_option_value(BYTE_STRING_VALUE(name), &value, (char_u **)&strval, opt_flags);
1760     curbuf = save_curb;
1761     curwin = save_curw;
1762 
1763     switch (rc)
1764     {
1765     case 1:
1766 	MZ_GC_UNREG();
1767 	return scheme_make_integer_value(value);
1768     case 0:
1769 	rval = scheme_make_byte_string(strval);
1770 	MZ_GC_CHECK();
1771 	vim_free(strval);
1772 	MZ_GC_UNREG();
1773 	return rval;
1774     case -1:
1775     case -2:
1776 	MZ_GC_UNREG();
1777 	raise_vim_exn(_("hidden option"));
1778     case -3:
1779 	MZ_GC_UNREG();
1780 	raise_vim_exn(_("unknown option"));
1781     }
1782     /* unreachable */
1783     return scheme_void;
1784 }
1785 
1786 /* (set-option {option-changing-string} [buffer/window]) */
1787     static Scheme_Object *
1788 set_option(void *data, int argc, Scheme_Object **argv)
1789 {
1790     char_u	*command = NULL;
1791     int		opt_flags = 0;
1792     buf_T	*save_curb = curbuf;
1793     win_T	*save_curw = curwin;
1794     Vim_Prim	*prim = (Vim_Prim *)data;
1795     Scheme_Object *cmd = NULL;
1796 
1797     MZ_GC_DECL_REG(1);
1798     MZ_GC_VAR_IN_REG(0, cmd);
1799     MZ_GC_REG();
1800     cmd = GUARANTEED_STRING_ARG(prim->name, 0);
1801 
1802     if (argc > 1)
1803     {
1804 	if (M_global == NULL)
1805 	{
1806 	    MZ_REGISTER_STATIC(M_global);
1807 	    M_global = scheme_intern_symbol("global");
1808 	    MZ_GC_CHECK();
1809 	}
1810 
1811 	if (argv[1] == M_global)
1812 	    opt_flags = OPT_GLOBAL;
1813 	else if (SCHEME_VIMBUFFERP(argv[1]))
1814 	{
1815 	    curbuf = get_valid_buffer(argv[1]);
1816 	    opt_flags = OPT_LOCAL;
1817 	}
1818 	else if (SCHEME_VIMWINDOWP(argv[1]))
1819 	{
1820 	    win_T *win = get_valid_window(argv[1]);
1821 	    curwin = win;
1822 	    curbuf = win->w_buffer;
1823 	    opt_flags = OPT_LOCAL;
1824 	}
1825 	else
1826 	    scheme_wrong_type(prim->name, "vim-buffer/window", 1, argc, argv);
1827     }
1828 
1829     /* do_set can modify cmd, make copy */
1830     command = vim_strsave(BYTE_STRING_VALUE(cmd));
1831     MZ_GC_UNREG();
1832     do_set(command, opt_flags);
1833     vim_free(command);
1834     update_screen(NOT_VALID);
1835     curbuf = save_curb;
1836     curwin = save_curw;
1837     raise_if_error();
1838     return scheme_void;
1839 }
1840 
1841 /*
1842  *===========================================================================
1843  *  5. Vim Window-related Manipulation Functions
1844  *===========================================================================
1845  */
1846 
1847 /* (curr-win) */
1848     static Scheme_Object *
1849 get_curr_win(void *data UNUSED, int argc UNUSED, Scheme_Object **argv UNUSED)
1850 {
1851     return (Scheme_Object *)get_vim_curr_window();
1852 }
1853 
1854 /* (win-count) */
1855     static Scheme_Object *
1856 get_window_count(void *data UNUSED, int argc UNUSED, Scheme_Object **argv UNUSED)
1857 {
1858     int	    n = 0;
1859     win_T   *w;
1860 
1861     FOR_ALL_WINDOWS(w)
1862 	++n;
1863     return scheme_make_integer(n);
1864 }
1865 
1866 /* (get-win-list [buffer]) */
1867     static Scheme_Object *
1868 get_window_list(void *data, int argc, Scheme_Object **argv)
1869 {
1870     Vim_Prim	    *prim = (Vim_Prim *)data;
1871     vim_mz_buffer   *buf;
1872     Scheme_Object   *list;
1873     win_T	    *w = firstwin;
1874 
1875     buf = get_buffer_arg(prim->name, 0, argc, argv);
1876     list = scheme_null;
1877 
1878     for ( ; w != NULL; w = w->w_next)
1879 	if (w->w_buffer == buf->buf)
1880 	{
1881 	    list = scheme_make_pair(window_new(w), list);
1882 	    MZ_GC_CHECK();
1883 	}
1884 
1885     return list;
1886 }
1887 
1888     static Scheme_Object *
1889 window_new(win_T *win)
1890 {
1891     vim_mz_window *self = NULL;
1892 
1893     MZ_GC_DECL_REG(1);
1894     MZ_GC_VAR_IN_REG(0, self);
1895 
1896     /* We need to handle deletion of windows underneath us.
1897      * If we add a "w_mzscheme_ref" field to the win_T structure,
1898      * then we can get at it in win_free() in vim.
1899      *
1900      * On a win_free() we set the Scheme object's win_T *field
1901      * to an invalid value. We trap all uses of a window
1902      * object, and reject them if the win_T *field is invalid.
1903      */
1904     if (win->w_mzscheme_ref != NULL)
1905 	return (Scheme_Object *)WINDOW_REF(win);
1906 
1907     MZ_GC_REG();
1908     self = scheme_malloc_fail_ok(scheme_malloc_tagged, sizeof(vim_mz_window));
1909     vim_memset(self, 0, sizeof(vim_mz_window));
1910 #ifndef MZ_PRECISE_GC
1911     scheme_dont_gc_ptr(self);	/* because win isn't visible to GC */
1912 #else
1913     win->w_mzscheme_ref = scheme_malloc_immobile_box(NULL);
1914 #endif
1915     MZ_GC_CHECK();
1916     WINDOW_REF(win) = self;
1917     MZ_GC_CHECK();
1918     self->win = win;
1919     self->so.type = mz_window_type;
1920 
1921     MZ_GC_UNREG();
1922     return (Scheme_Object *)self;
1923 }
1924 
1925 /* (get-win-num [window]) */
1926     static Scheme_Object *
1927 get_window_num(void *data UNUSED, int argc UNUSED, Scheme_Object **argv UNUSED)
1928 {
1929     int		nr = 1;
1930     Vim_Prim	*prim = (Vim_Prim *)data;
1931     win_T	*win = get_window_arg(prim->name, 0, argc, argv)->win;
1932     win_T	*wp;
1933 
1934     for (wp = firstwin; wp != win; wp = wp->w_next)
1935 	++nr;
1936 
1937     return scheme_make_integer(nr);
1938 }
1939 
1940 /* (get-win-by-num {windownum}) */
1941     static Scheme_Object *
1942 get_window_by_num(void *data, int argc, Scheme_Object **argv)
1943 {
1944     Vim_Prim	*prim = (Vim_Prim *)data;
1945     win_T	*win = firstwin;
1946     int		fnum;
1947 
1948     fnum = SCHEME_INT_VAL(GUARANTEE_INTEGER(prim->name, 0));
1949     if (fnum < 1)
1950 	scheme_signal_error(_("window index is out of range"));
1951 
1952     for ( ; win != NULL; win = win->w_next, --fnum)
1953 	if (fnum == 1)	    /* to be 1-based */
1954 	    return window_new(win);
1955 
1956     return scheme_false;
1957 }
1958 
1959 /* (get-win-buffer [window]) */
1960     static Scheme_Object *
1961 get_window_buffer(void *data, int argc, Scheme_Object **argv)
1962 {
1963     Vim_Prim	    *prim = (Vim_Prim *)data;
1964     vim_mz_window   *win = get_window_arg(prim->name, 0, argc, argv);
1965 
1966     return buffer_new(win->win->w_buffer);
1967 }
1968 
1969 /* (get-win-height [window]) */
1970     static Scheme_Object *
1971 get_window_height(void *data, int argc, Scheme_Object **argv)
1972 {
1973     Vim_Prim	    *prim = (Vim_Prim *)data;
1974     vim_mz_window   *win = get_window_arg(prim->name, 0, argc, argv);
1975 
1976     return scheme_make_integer(win->win->w_height);
1977 }
1978 
1979 /* (set-win-height {height} [window]) */
1980     static Scheme_Object *
1981 set_window_height(void *data, int argc, Scheme_Object **argv)
1982 {
1983     Vim_Prim	    *prim = (Vim_Prim *)data;
1984     vim_mz_window   *win;
1985     win_T	    *savewin;
1986     int		    height;
1987 
1988     win = get_window_arg(prim->name, 1, argc, argv);
1989     height = SCHEME_INT_VAL(GUARANTEE_INTEGER(prim->name, 0));
1990 
1991 #ifdef FEAT_GUI
1992     need_mouse_correct = TRUE;
1993 #endif
1994 
1995     savewin = curwin;
1996     curwin = win->win;
1997     win_setheight(height);
1998     curwin = savewin;
1999 
2000     raise_if_error();
2001     return scheme_void;
2002 }
2003 
2004 /* (get-win-width [window]) */
2005     static Scheme_Object *
2006 get_window_width(void *data, int argc, Scheme_Object **argv)
2007 {
2008     Vim_Prim	    *prim = (Vim_Prim *)data;
2009     vim_mz_window   *win = get_window_arg(prim->name, 0, argc, argv);
2010 
2011     return scheme_make_integer(win->win->w_width);
2012 }
2013 
2014 /* (set-win-width {width} [window]) */
2015     static Scheme_Object *
2016 set_window_width(void *data, int argc, Scheme_Object **argv)
2017 {
2018     Vim_Prim	    *prim = (Vim_Prim *)data;
2019     vim_mz_window   *win;
2020     win_T	    *savewin;
2021     int		    width = 0;
2022 
2023     win = get_window_arg(prim->name, 1, argc, argv);
2024     width = SCHEME_INT_VAL(GUARANTEE_INTEGER(prim->name, 0));
2025 
2026 # ifdef FEAT_GUI
2027     need_mouse_correct = TRUE;
2028 # endif
2029 
2030     savewin = curwin;
2031     curwin = win->win;
2032     win_setwidth(width);
2033     curwin = savewin;
2034 
2035     raise_if_error();
2036     return scheme_void;
2037 }
2038 
2039 /* (get-cursor [window]) -> (line . col) */
2040     static Scheme_Object *
2041 get_cursor(void *data, int argc, Scheme_Object **argv)
2042 {
2043     Vim_Prim	    *prim = (Vim_Prim *)data;
2044     vim_mz_window   *win;
2045     pos_T	    pos;
2046 
2047     win = get_window_arg(prim->name, 0, argc, argv);
2048     pos = win->win->w_cursor;
2049     return scheme_make_pair(scheme_make_integer_value((long)pos.lnum),
2050 		    scheme_make_integer_value((long)pos.col + 1));
2051 }
2052 
2053 /* (set-cursor (line . col) [window]) */
2054     static Scheme_Object *
2055 set_cursor(void *data, int argc, Scheme_Object **argv)
2056 {
2057     Vim_Prim	    *prim = (Vim_Prim *)data;
2058     vim_mz_window   *win;
2059     long	    lnum = 0;
2060     long	    col = 0;
2061 
2062 #ifdef HAVE_SANDBOX
2063     sandbox_check();
2064 #endif
2065     win = get_window_arg(prim->name, 1, argc, argv);
2066     GUARANTEE_PAIR(prim->name, 0);
2067 
2068     if (!SCHEME_INTP(SCHEME_CAR(argv[0]))
2069 	    || !SCHEME_INTP(SCHEME_CDR(argv[0])))
2070 	scheme_wrong_type(prim->name, "integer pair", 0, argc, argv);
2071 
2072     lnum = SCHEME_INT_VAL(SCHEME_CAR(argv[0]));
2073     col = SCHEME_INT_VAL(SCHEME_CDR(argv[0])) - 1;
2074 
2075     check_line_range(lnum, win->win->w_buffer);
2076     /* don't know how to catch invalid column value */
2077 
2078     win->win->w_cursor.lnum = lnum;
2079     win->win->w_cursor.col = col;
2080     win->win->w_set_curswant = TRUE;
2081     update_screen(VALID);
2082 
2083     raise_if_error();
2084     return scheme_void;
2085 }
2086 /*
2087  *===========================================================================
2088  *  6. Vim Buffer-related Manipulation Functions
2089  *===========================================================================
2090  */
2091 
2092 /* (open-buff {filename}) */
2093     static Scheme_Object *
2094 mzscheme_open_buffer(void *data, int argc, Scheme_Object **argv)
2095 {
2096     Vim_Prim	    *prim = (Vim_Prim *)data;
2097     int		    num = 0;
2098     Scheme_Object   *onum = NULL;
2099     Scheme_Object   *buf = NULL;
2100     Scheme_Object   *fname;
2101 
2102     MZ_GC_DECL_REG(3);
2103     MZ_GC_VAR_IN_REG(0, onum);
2104     MZ_GC_VAR_IN_REG(1, buf);
2105     MZ_GC_VAR_IN_REG(2, fname);
2106     MZ_GC_REG();
2107     fname = GUARANTEED_STRING_ARG(prim->name, 0);
2108 
2109 #ifdef HAVE_SANDBOX
2110     sandbox_check();
2111 #endif
2112     /* TODO make open existing file */
2113     num = buflist_add(BYTE_STRING_VALUE(fname), BLN_LISTED | BLN_CURBUF);
2114 
2115     if (num == 0)
2116 	raise_vim_exn(_("couldn't open buffer"));
2117 
2118     onum = scheme_make_integer(num);
2119     buf = get_buffer_by_num(data, 1, &onum);
2120     MZ_GC_UNREG();
2121     return buf;
2122 }
2123 
2124 /* (get-buff-by-num {buffernum}) */
2125     static Scheme_Object *
2126 get_buffer_by_num(void *data, int argc, Scheme_Object **argv)
2127 {
2128     Vim_Prim	*prim = (Vim_Prim *)data;
2129     buf_T	*buf;
2130     int		fnum;
2131 
2132     fnum = SCHEME_INT_VAL(GUARANTEE_INTEGER(prim->name, 0));
2133 
2134     FOR_ALL_BUFFERS(buf)
2135 	if (buf->b_fnum == fnum)
2136 	    return buffer_new(buf);
2137 
2138     return scheme_false;
2139 }
2140 
2141 /* (get-buff-by-name {buffername}) */
2142     static Scheme_Object *
2143 get_buffer_by_name(void *data, int argc, Scheme_Object **argv)
2144 {
2145     Vim_Prim	*prim = (Vim_Prim *)data;
2146     buf_T	*buf;
2147     Scheme_Object *buffer = NULL;
2148     Scheme_Object *fname = NULL;
2149 
2150     MZ_GC_DECL_REG(2);
2151     MZ_GC_VAR_IN_REG(0, buffer);
2152     MZ_GC_VAR_IN_REG(1, fname);
2153     MZ_GC_REG();
2154     fname = GUARANTEED_STRING_ARG(prim->name, 0);
2155     buffer = scheme_false;
2156 
2157     FOR_ALL_BUFFERS(buf)
2158     {
2159 	if (buf->b_ffname == NULL || buf->b_sfname == NULL)
2160 	    /* empty string */
2161 	{
2162 	    if (BYTE_STRING_VALUE(fname)[0] == NUL)
2163 		buffer = buffer_new(buf);
2164 	}
2165 	else if (!fnamecmp(buf->b_ffname, BYTE_STRING_VALUE(fname))
2166 		|| !fnamecmp(buf->b_sfname, BYTE_STRING_VALUE(fname)))
2167 	{
2168 	    /* either short or long filename matches */
2169 	    buffer = buffer_new(buf);
2170 	}
2171     }
2172 
2173     MZ_GC_UNREG();
2174     return buffer;
2175 }
2176 
2177 /* (get-next-buff [buffer]) */
2178     static Scheme_Object *
2179 get_next_buffer(void *data, int argc, Scheme_Object **argv)
2180 {
2181     Vim_Prim	*prim = (Vim_Prim *)data;
2182     buf_T	*buf = get_buffer_arg(prim->name, 0, argc, argv)->buf;
2183 
2184     if (buf->b_next == NULL)
2185 	return scheme_false;
2186     else
2187 	return buffer_new(buf->b_next);
2188 }
2189 
2190 /* (get-prev-buff [buffer]) */
2191     static Scheme_Object *
2192 get_prev_buffer(void *data, int argc, Scheme_Object **argv)
2193 {
2194     Vim_Prim	*prim = (Vim_Prim *)data;
2195     buf_T	*buf = get_buffer_arg(prim->name, 0, argc, argv)->buf;
2196 
2197     if (buf->b_prev == NULL)
2198 	return scheme_false;
2199     else
2200 	return buffer_new(buf->b_prev);
2201 }
2202 
2203 /* (get-buff-num [buffer]) */
2204     static Scheme_Object *
2205 get_buffer_num(void *data, int argc, Scheme_Object **argv)
2206 {
2207     Vim_Prim	    *prim = (Vim_Prim *)data;
2208     vim_mz_buffer   *buf = get_buffer_arg(prim->name, 0, argc, argv);
2209 
2210     return scheme_make_integer(buf->buf->b_fnum);
2211 }
2212 
2213 /* (buff-count) */
2214     static Scheme_Object *
2215 get_buffer_count(void *data UNUSED, int argc UNUSED, Scheme_Object **argv UNUSED)
2216 {
2217     buf_T   *b;
2218     int	    n = 0;
2219 
2220     FOR_ALL_BUFFERS(b) ++n;
2221     return scheme_make_integer(n);
2222 }
2223 
2224 /* (get-buff-name [buffer]) */
2225     static Scheme_Object *
2226 get_buffer_name(void *data, int argc, Scheme_Object **argv)
2227 {
2228     Vim_Prim	    *prim = (Vim_Prim *)data;
2229     vim_mz_buffer   *buf = get_buffer_arg(prim->name, 0, argc, argv);
2230 
2231     return scheme_make_byte_string((char *)buf->buf->b_ffname);
2232 }
2233 
2234 /* (curr-buff) */
2235     static Scheme_Object *
2236 get_curr_buffer(void *data UNUSED, int argc UNUSED, Scheme_Object **argv UNUSED)
2237 {
2238     return (Scheme_Object *)get_vim_curr_buffer();
2239 }
2240 
2241     static Scheme_Object *
2242 buffer_new(buf_T *buf)
2243 {
2244     vim_mz_buffer *self = NULL;
2245 
2246     MZ_GC_DECL_REG(1);
2247     MZ_GC_VAR_IN_REG(0, self);
2248 
2249     /* We need to handle deletion of buffers underneath us.
2250      * If we add a "b_mzscheme_ref" field to the buf_T structure,
2251      * then we can get at it in buf_freeall() in vim.
2252      */
2253     if (buf->b_mzscheme_ref)
2254 	return (Scheme_Object *)BUFFER_REF(buf);
2255 
2256     MZ_GC_REG();
2257     self = scheme_malloc_fail_ok(scheme_malloc_tagged, sizeof(vim_mz_buffer));
2258     vim_memset(self, 0, sizeof(vim_mz_buffer));
2259 #ifndef MZ_PRECISE_GC
2260     scheme_dont_gc_ptr(self);	/* because buf isn't visible to GC */
2261 #else
2262     buf->b_mzscheme_ref = scheme_malloc_immobile_box(NULL);
2263 #endif
2264     MZ_GC_CHECK();
2265     BUFFER_REF(buf) = self;
2266     MZ_GC_CHECK();
2267     self->buf = buf;
2268     self->so.type = mz_buffer_type;
2269 
2270     MZ_GC_UNREG();
2271     return (Scheme_Object *)self;
2272 }
2273 
2274 /*
2275  * (get-buff-size [buffer])
2276  *
2277  * Get the size (number of lines) in the current buffer.
2278  */
2279     static Scheme_Object *
2280 get_buffer_size(void *data, int argc, Scheme_Object **argv)
2281 {
2282     Vim_Prim	    *prim = (Vim_Prim *)data;
2283     vim_mz_buffer   *buf = get_buffer_arg(prim->name, 0, argc, argv);
2284 
2285     return scheme_make_integer(buf->buf->b_ml.ml_line_count);
2286 }
2287 
2288 /*
2289  * (get-buff-line {linenr} [buffer])
2290  *
2291  * Get a line from the specified buffer. The line number is
2292  * in Vim format (1-based). The line is returned as a MzScheme
2293  * string object.
2294  */
2295     static Scheme_Object *
2296 get_buffer_line(void *data, int argc, Scheme_Object **argv)
2297 {
2298     Vim_Prim	    *prim = (Vim_Prim *)data;
2299     vim_mz_buffer   *buf;
2300     int		    linenr;
2301     char_u	    *line;
2302 
2303     buf = get_buffer_arg(prim->name, 1, argc, argv);
2304     linenr = SCHEME_INT_VAL(GUARANTEE_INTEGER(prim->name, 0));
2305     line = ml_get_buf(buf->buf, (linenr_T)linenr, FALSE);
2306 
2307     raise_if_error();
2308     return scheme_make_byte_string((char *)line);
2309 }
2310 
2311 
2312 /*
2313  * (get-buff-line-list {start} {end} [buffer])
2314  *
2315  * Get a list of lines from the specified buffer. The line numbers
2316  * are in Vim format (1-based). The range is from lo up to, but not
2317  * including, hi. The list is returned as a list of string objects.
2318  */
2319     static Scheme_Object *
2320 get_buffer_line_list(void *data, int argc, Scheme_Object **argv)
2321 {
2322     Vim_Prim	    *prim = (Vim_Prim *)data;
2323     vim_mz_buffer   *buf;
2324     int		    i, hi, lo, n;
2325     Scheme_Object   *list = NULL;
2326 
2327     MZ_GC_DECL_REG(1);
2328     MZ_GC_VAR_IN_REG(0, list);
2329     MZ_GC_REG();
2330 
2331     buf = get_buffer_arg(prim->name, 2, argc, argv);
2332     list = scheme_null;
2333     hi = SCHEME_INT_VAL(GUARANTEE_INTEGER(prim->name, 1));
2334     lo = SCHEME_INT_VAL(GUARANTEE_INTEGER(prim->name, 0));
2335 
2336     /*
2337      * Handle some error conditions
2338      */
2339     if (lo < 0)
2340 	lo = 0;
2341 
2342     if (hi < 0)
2343 	hi = 0;
2344     if (hi < lo)
2345 	hi = lo;
2346 
2347     n = hi - lo;
2348 
2349     for (i = n; i >= 0; --i)
2350     {
2351 	Scheme_Object *str = scheme_make_byte_string(
2352 		       (char *)ml_get_buf(buf->buf, (linenr_T)(lo+i), FALSE));
2353 	raise_if_error();
2354 
2355 	/* Set the list item */
2356 	list = scheme_make_pair(str, list);
2357 	MZ_GC_CHECK();
2358     }
2359     MZ_GC_UNREG();
2360     return list;
2361 }
2362 
2363 /*
2364  * (set-buff-line {linenr} {string/#f} [buffer])
2365  *
2366  * Replace a line in the specified buffer. The line number is
2367  * in Vim format (1-based). The replacement line is given as
2368  * an MzScheme string object. The object is checked for validity
2369  * and correct format. An exception is thrown if the values are not
2370  * the correct format.
2371  *
2372  * It returns a Scheme Object that indicates the length of the
2373  * string changed.
2374  */
2375     static Scheme_Object *
2376 set_buffer_line(void *data, int argc, Scheme_Object **argv)
2377 {
2378     /* First of all, we check the value of the supplied MzScheme object.
2379      * There are three cases:
2380      *	  1. #f - this is a deletion.
2381      *	  2. A string	   - this is a replacement.
2382      *	  3. Anything else - this is an error.
2383      */
2384     Vim_Prim	    *prim = (Vim_Prim *)data;
2385     vim_mz_buffer   *buf;
2386     Scheme_Object   *line = NULL;
2387     char	    *save;
2388     int		    n;
2389 
2390     MZ_GC_DECL_REG(1);
2391     MZ_GC_VAR_IN_REG(0, line);
2392     MZ_GC_REG();
2393 
2394 #ifdef HAVE_SANDBOX
2395     sandbox_check();
2396 #endif
2397     n = SCHEME_INT_VAL(GUARANTEE_INTEGER(prim->name, 0));
2398     if (!SCHEME_STRINGP(argv[1]) && !SCHEME_FALSEP(argv[1]))
2399 	scheme_wrong_type(prim->name, "string or #f", 1, argc, argv);
2400     line = argv[1];
2401     buf = get_buffer_arg(prim->name, 2, argc, argv);
2402 
2403     check_line_range(n, buf->buf);
2404 
2405     if (SCHEME_FALSEP(line))
2406     {
2407 	buf_T	    *savebuf = curbuf;
2408 
2409 	curbuf = buf->buf;
2410 
2411 	if (u_savedel((linenr_T)n, 1L) == FAIL)
2412 	{
2413 	    curbuf = savebuf;
2414 	    raise_vim_exn(_("cannot save undo information"));
2415 	}
2416 	else if (ml_delete((linenr_T)n, FALSE) == FAIL)
2417 	{
2418 	    curbuf = savebuf;
2419 	    raise_vim_exn(_("cannot delete line"));
2420 	}
2421 	if (buf->buf == curwin->w_buffer)
2422 	    mz_fix_cursor(n, n + 1, -1);
2423 	deleted_lines_mark((linenr_T)n, 1L);
2424 
2425 	curbuf = savebuf;
2426 
2427 	MZ_GC_UNREG();
2428 	raise_if_error();
2429 	return scheme_void;
2430     }
2431     else
2432     {
2433 	/* Otherwise it's a line */
2434 	buf_T	    *savebuf = curbuf;
2435 
2436 	save = string_to_line(line);
2437 
2438 	curbuf = buf->buf;
2439 
2440 	if (u_savesub((linenr_T)n) == FAIL)
2441 	{
2442 	    curbuf = savebuf;
2443 	    vim_free(save);
2444 	    raise_vim_exn(_("cannot save undo information"));
2445 	}
2446 	else if (ml_replace((linenr_T)n, (char_u *)save, TRUE) == FAIL)
2447 	{
2448 	    curbuf = savebuf;
2449 	    vim_free(save);
2450 	    raise_vim_exn(_("cannot replace line"));
2451 	}
2452 	else
2453 	{
2454 	    vim_free(save);
2455 	    changed_bytes((linenr_T)n, 0);
2456 	}
2457 
2458 	curbuf = savebuf;
2459 
2460 	/* Check that the cursor is not beyond the end of the line now. */
2461 	if (buf->buf == curwin->w_buffer)
2462 	    check_cursor_col();
2463 
2464 	MZ_GC_UNREG();
2465 	raise_if_error();
2466 	return scheme_void;
2467     }
2468 }
2469 
2470     static void
2471 free_array(char **array)
2472 {
2473     char **curr = array;
2474     while (*curr != NULL)
2475 	vim_free(*curr++);
2476     vim_free(array);
2477 }
2478 
2479 /*
2480  * (set-buff-line-list {start} {end} {string-list/#f/null} [buffer])
2481  *
2482  * Replace a range of lines in the specified buffer. The line numbers are in
2483  * Vim format (1-based). The range is from lo up to, but not including, hi.
2484  * The replacement lines are given as a Scheme list of string objects. The
2485  * list is checked for validity and correct format.
2486  *
2487  * Errors are returned as a value of FAIL. The return value is OK on success.
2488  * If OK is returned and len_change is not NULL, *len_change is set to the
2489  * change in the buffer length.
2490  */
2491     static Scheme_Object *
2492 set_buffer_line_list(void *data, int argc, Scheme_Object **argv)
2493 {
2494     /* First of all, we check the type of the supplied MzScheme object.
2495      * There are three cases:
2496      *	  1. #f - this is a deletion.
2497      *	  2. A list	   - this is a replacement.
2498      *	  3. Anything else - this is an error.
2499      */
2500     Vim_Prim	    *prim = (Vim_Prim *)data;
2501     vim_mz_buffer   *buf = NULL;
2502     Scheme_Object   *line_list = NULL;
2503     int		    i, old_len, new_len, hi, lo;
2504     long	    extra;
2505 
2506     MZ_GC_DECL_REG(1);
2507     MZ_GC_VAR_IN_REG(0, line_list);
2508     MZ_GC_REG();
2509 
2510 #ifdef HAVE_SANDBOX
2511     sandbox_check();
2512 #endif
2513     lo = SCHEME_INT_VAL(GUARANTEE_INTEGER(prim->name, 0));
2514     hi = SCHEME_INT_VAL(GUARANTEE_INTEGER(prim->name, 1));
2515     if (!SCHEME_PAIRP(argv[2])
2516 	    && !SCHEME_FALSEP(argv[2]) && !SCHEME_NULLP(argv[2]))
2517 	scheme_wrong_type(prim->name, "list or #f", 2, argc, argv);
2518     line_list = argv[2];
2519     buf = get_buffer_arg(prim->name, 3, argc, argv);
2520     old_len = hi - lo;
2521     if (old_len < 0) /* process inverse values wisely */
2522     {
2523 	i = lo;
2524 	lo = hi;
2525 	hi = i;
2526 	old_len = -old_len;
2527     }
2528     extra = 0;
2529 
2530     check_line_range(lo, buf->buf);	    /* inclusive */
2531     check_line_range(hi - 1, buf->buf);	    /* exclusive */
2532 
2533     if (SCHEME_FALSEP(line_list) || SCHEME_NULLP(line_list))
2534     {
2535 	buf_T	*savebuf = curbuf;
2536 	curbuf = buf->buf;
2537 
2538 	if (u_savedel((linenr_T)lo, (long)old_len) == FAIL)
2539 	{
2540 	    curbuf = savebuf;
2541 	    raise_vim_exn(_("cannot save undo information"));
2542 	}
2543 	else
2544 	{
2545 	    for (i = 0; i < old_len; i++)
2546 		if (ml_delete((linenr_T)lo, FALSE) == FAIL)
2547 		{
2548 		    curbuf = savebuf;
2549 		    raise_vim_exn(_("cannot delete line"));
2550 		}
2551 	    if (buf->buf == curwin->w_buffer)
2552 		mz_fix_cursor(lo, hi, -old_len);
2553 	    deleted_lines_mark((linenr_T)lo, (long)old_len);
2554 	}
2555 
2556 	curbuf = savebuf;
2557 
2558 	MZ_GC_UNREG();
2559 	raise_if_error();
2560 	return scheme_void;
2561     }
2562     else
2563     {
2564 	buf_T	*savebuf = curbuf;
2565 
2566 	/* List */
2567 	new_len = scheme_proper_list_length(line_list);
2568 	MZ_GC_CHECK();
2569 	if (new_len < 0)	/* improper or cyclic list */
2570 	    scheme_wrong_type(prim->name, "proper list",
2571 		    2, argc, argv);
2572 	else
2573 	{
2574 	    char		**array = NULL;
2575 	    Scheme_Object   *line = NULL;
2576 	    Scheme_Object   *rest = NULL;
2577 
2578 	    MZ_GC_DECL_REG(2);
2579 	    MZ_GC_VAR_IN_REG(0, line);
2580 	    MZ_GC_VAR_IN_REG(1, rest);
2581 	    MZ_GC_REG();
2582 
2583 	    array = (char **)alloc((new_len+1)* sizeof(char *));
2584 	    vim_memset(array, 0, (new_len+1) * sizeof(char *));
2585 
2586 	    rest = line_list;
2587 	    for (i = 0; i < new_len; ++i)
2588 	    {
2589 		line = SCHEME_CAR(rest);
2590 		rest = SCHEME_CDR(rest);
2591 		if (!SCHEME_STRINGP(line))
2592 		{
2593 		    free_array(array);
2594 		    scheme_wrong_type(prim->name, "string-list", 2, argc, argv);
2595 		}
2596 		array[i] = string_to_line(line);
2597 	    }
2598 
2599 	    curbuf = buf->buf;
2600 
2601 	    if (u_save((linenr_T)(lo-1), (linenr_T)hi) == FAIL)
2602 	    {
2603 		curbuf = savebuf;
2604 		free_array(array);
2605 		raise_vim_exn(_("cannot save undo information"));
2606 	    }
2607 
2608 	    /*
2609 	     * If the size of the range is reducing (ie, new_len < old_len) we
2610 	     * need to delete some old_len. We do this at the start, by
2611 	     * repeatedly deleting line "lo".
2612 	     */
2613 	    for (i = 0; i < old_len - new_len; ++i)
2614 	    {
2615 		if (ml_delete((linenr_T)lo, FALSE) == FAIL)
2616 		{
2617 		    curbuf = savebuf;
2618 		    free_array(array);
2619 		    raise_vim_exn(_("cannot delete line"));
2620 		}
2621 		extra--;
2622 	    }
2623 
2624 	    /*
2625 	     * For as long as possible, replace the existing old_len with the
2626 	     * new old_len. This is a more efficient operation, as it requires
2627 	     * less memory allocation and freeing.
2628 	     */
2629 	    for (i = 0; i < old_len && i < new_len; i++)
2630 		if (ml_replace((linenr_T)(lo+i), (char_u *)array[i], TRUE) == FAIL)
2631 		{
2632 		    curbuf = savebuf;
2633 		    free_array(array);
2634 		    raise_vim_exn(_("cannot replace line"));
2635 		}
2636 
2637 	    /*
2638 	     * Now we may need to insert the remaining new_len.  We don't need to
2639 	     * free the string passed back because MzScheme has control of that
2640 	     * memory.
2641 	     */
2642 	    while (i < new_len)
2643 	    {
2644 		if (ml_append((linenr_T)(lo + i - 1),
2645 			    (char_u *)array[i], 0, FALSE) == FAIL)
2646 		{
2647 		    curbuf = savebuf;
2648 		    free_array(array);
2649 		    raise_vim_exn(_("cannot insert line"));
2650 		}
2651 		++i;
2652 		++extra;
2653 	    }
2654 	    MZ_GC_UNREG();
2655 	    free_array(array);
2656 	}
2657 
2658 	/*
2659 	 * Adjust marks. Invalidate any which lie in the
2660 	 * changed range, and move any in the remainder of the buffer.
2661 	 */
2662 	mark_adjust((linenr_T)lo, (linenr_T)(hi - 1),
2663 						  (long)MAXLNUM, (long)extra);
2664 	changed_lines((linenr_T)lo, 0, (linenr_T)hi, (long)extra);
2665 
2666 	if (buf->buf == curwin->w_buffer)
2667 	    mz_fix_cursor(lo, hi, extra);
2668 	curbuf = savebuf;
2669 
2670 	MZ_GC_UNREG();
2671 	raise_if_error();
2672 	return scheme_void;
2673     }
2674 }
2675 
2676 /*
2677  * (insert-buff-line-list {linenr} {string/string-list} [buffer])
2678  *
2679  * Insert a number of lines into the specified buffer after the specified line.
2680  * The line number is in Vim format (1-based). The lines to be inserted are
2681  * given as an MzScheme list of string objects or as a single string. The lines
2682  * to be added are checked for validity and correct format. Errors are
2683  * returned as a value of FAIL.  The return value is OK on success.
2684  * If OK is returned and len_change is not NULL, *len_change
2685  * is set to the change in the buffer length.
2686  */
2687     static Scheme_Object *
2688 insert_buffer_line_list(void *data, int argc, Scheme_Object **argv)
2689 {
2690     Vim_Prim	    *prim = (Vim_Prim *)data;
2691     vim_mz_buffer   *buf = NULL;
2692     Scheme_Object   *list = NULL;
2693     char	    *str = NULL;
2694     int		    i, n, size;
2695 
2696     MZ_GC_DECL_REG(1);
2697     MZ_GC_VAR_IN_REG(0, list);
2698     MZ_GC_REG();
2699 
2700 #ifdef HAVE_SANDBOX
2701     sandbox_check();
2702 #endif
2703     /*
2704      * First of all, we check the type of the supplied MzScheme object.
2705      * It must be a string or a list, or the call is in error.
2706      */
2707     n = SCHEME_INT_VAL(GUARANTEE_INTEGER(prim->name, 0));
2708     list = argv[1];
2709 
2710     if (!SCHEME_STRINGP(list) && !SCHEME_PAIRP(list))
2711 	scheme_wrong_type(prim->name, "string or list", 1, argc, argv);
2712     buf = get_buffer_arg(prim->name, 2, argc, argv);
2713 
2714     if (n != 0)	    /* 0 can be used in insert */
2715 	check_line_range(n, buf->buf);
2716     if (SCHEME_STRINGP(list))
2717     {
2718 	buf_T	    *savebuf = curbuf;
2719 
2720 	str = string_to_line(list);
2721 	curbuf = buf->buf;
2722 
2723 	if (u_save((linenr_T)n, (linenr_T)(n+1)) == FAIL)
2724 	{
2725 	    curbuf = savebuf;
2726 	    vim_free(str);
2727 	    raise_vim_exn(_("cannot save undo information"));
2728 	}
2729 	else if (ml_append((linenr_T)n, (char_u *)str, 0, FALSE) == FAIL)
2730 	{
2731 	    curbuf = savebuf;
2732 	    vim_free(str);
2733 	    raise_vim_exn(_("cannot insert line"));
2734 	}
2735 	else
2736 	{
2737 	    vim_free(str);
2738 	    appended_lines_mark((linenr_T)n, 1L);
2739 	}
2740 
2741 	curbuf = savebuf;
2742 	update_screen(VALID);
2743 
2744 	MZ_GC_UNREG();
2745 	raise_if_error();
2746 	return scheme_void;
2747     }
2748 
2749     /* List */
2750     size = scheme_proper_list_length(list);
2751     MZ_GC_CHECK();
2752     if (size < 0)	/* improper or cyclic list */
2753 	scheme_wrong_type(prim->name, "proper list",
2754 		2, argc, argv);
2755     else
2756     {
2757 	Scheme_Object   *line = NULL;
2758 	Scheme_Object   *rest = NULL;
2759 	char		**array;
2760 	buf_T		*savebuf = curbuf;
2761 
2762 	MZ_GC_DECL_REG(2);
2763 	MZ_GC_VAR_IN_REG(0, line);
2764 	MZ_GC_VAR_IN_REG(1, rest);
2765 	MZ_GC_REG();
2766 
2767 	array = (char **)alloc((size+1) * sizeof(char *));
2768 	vim_memset(array, 0, (size+1) * sizeof(char *));
2769 
2770 	rest = list;
2771 	for (i = 0; i < size; ++i)
2772 	{
2773 	    line = SCHEME_CAR(rest);
2774 	    rest = SCHEME_CDR(rest);
2775 	    array[i] = string_to_line(line);
2776 	}
2777 
2778 	curbuf = buf->buf;
2779 
2780 	if (u_save((linenr_T)n, (linenr_T)(n + 1)) == FAIL)
2781 	{
2782 	    curbuf = savebuf;
2783 	    free_array(array);
2784 	    raise_vim_exn(_("cannot save undo information"));
2785 	}
2786 	else
2787 	{
2788 	    for (i = 0; i < size; ++i)
2789 		if (ml_append((linenr_T)(n + i), (char_u *)array[i],
2790 			    0, FALSE) == FAIL)
2791 		{
2792 		    curbuf = savebuf;
2793 		    free_array(array);
2794 		    raise_vim_exn(_("cannot insert line"));
2795 		}
2796 
2797 	    if (i > 0)
2798 		appended_lines_mark((linenr_T)n, (long)i);
2799 	}
2800 	free_array(array);
2801 	MZ_GC_UNREG();
2802 	curbuf = savebuf;
2803 	update_screen(VALID);
2804     }
2805 
2806     MZ_GC_UNREG();
2807     raise_if_error();
2808     return scheme_void;
2809 }
2810 
2811 /*
2812  * Predicates
2813  */
2814 /* (buff? obj) */
2815     static Scheme_Object *
2816 vim_bufferp(void *data UNUSED, int argc UNUSED, Scheme_Object **argv)
2817 {
2818     if (SCHEME_VIMBUFFERP(argv[0]))
2819 	return scheme_true;
2820     else
2821 	return scheme_false;
2822 }
2823 
2824 /* (win? obj) */
2825     static Scheme_Object *
2826 vim_windowp(void *data UNUSED, int argc UNUSED, Scheme_Object **argv)
2827 {
2828     if (SCHEME_VIMWINDOWP(argv[0]))
2829 	return scheme_true;
2830     else
2831 	return scheme_false;
2832 }
2833 
2834 /* (buff-valid? obj) */
2835     static Scheme_Object *
2836 vim_buffer_validp(void *data UNUSED, int argc UNUSED, Scheme_Object **argv)
2837 {
2838     if (SCHEME_VIMBUFFERP(argv[0])
2839 	    && ((vim_mz_buffer *)argv[0])->buf != INVALID_BUFFER_VALUE)
2840 	return scheme_true;
2841     else
2842 	return scheme_false;
2843 }
2844 
2845 /* (win-valid? obj) */
2846     static Scheme_Object *
2847 vim_window_validp(void *data UNUSED, int argc UNUSED, Scheme_Object **argv)
2848 {
2849     if (SCHEME_VIMWINDOWP(argv[0])
2850 	    && ((vim_mz_window *)argv[0])->win != INVALID_WINDOW_VALUE)
2851 	return scheme_true;
2852     else
2853 	return scheme_false;
2854 }
2855 
2856 /*
2857  *===========================================================================
2858  * Utilities
2859  *===========================================================================
2860  */
2861 
2862 /*
2863  * Convert an MzScheme string into a Vim line.
2864  *
2865  * All internal nulls are replaced by newline characters.
2866  * It is an error for the string to contain newline characters.
2867  *
2868  * Returns pointer to Vim allocated memory
2869  */
2870     static char *
2871 string_to_line(Scheme_Object *obj)
2872 {
2873     char	*scheme_str = NULL;
2874     char	*vim_str = NULL;
2875     OUTPUT_LEN_TYPE	len;
2876     int		i;
2877 
2878     scheme_str = scheme_display_to_string(obj, &len);
2879 
2880     /* Error checking: String must not contain newlines, as we
2881      * are replacing a single line, and we must replace it with
2882      * a single line.
2883      */
2884     if (memchr(scheme_str, '\n', len))
2885 	scheme_signal_error(_("string cannot contain newlines"));
2886 
2887     vim_str = (char *)alloc(len + 1);
2888 
2889     /* Create a copy of the string, with internal nulls replaced by
2890      * newline characters, as is the vim convention.
2891      */
2892     for (i = 0; i < len; ++i)
2893     {
2894 	if (scheme_str[i] == '\0')
2895 	    vim_str[i] = '\n';
2896 	else
2897 	    vim_str[i] = scheme_str[i];
2898     }
2899 
2900     vim_str[i] = '\0';
2901 
2902     MZ_GC_CHECK();
2903     return vim_str;
2904 }
2905 
2906 #ifdef FEAT_EVAL
2907 /*
2908  * Convert Vim value into MzScheme, adopted from if_python.c
2909  */
2910     static Scheme_Object *
2911 vim_to_mzscheme(typval_T *vim_value)
2912 {
2913     Scheme_Object	*result = NULL;
2914     /* hash table to store visited values to avoid infinite loops */
2915     Scheme_Hash_Table	*visited = NULL;
2916 
2917     MZ_GC_DECL_REG(2);
2918     MZ_GC_VAR_IN_REG(0, result);
2919     MZ_GC_VAR_IN_REG(1, visited);
2920     MZ_GC_REG();
2921 
2922     visited = scheme_make_hash_table(SCHEME_hash_ptr);
2923     MZ_GC_CHECK();
2924 
2925     result = vim_to_mzscheme_impl(vim_value, 1, visited);
2926 
2927     MZ_GC_UNREG();
2928     return result;
2929 }
2930 
2931     static Scheme_Object *
2932 vim_to_mzscheme_impl(typval_T *vim_value, int depth, Scheme_Hash_Table *visited)
2933 {
2934     Scheme_Object   *result = NULL;
2935     int		    new_value = TRUE;
2936 
2937     MZ_GC_DECL_REG(2);
2938     MZ_GC_VAR_IN_REG(0, result);
2939     MZ_GC_VAR_IN_REG(1, visited);
2940     MZ_GC_REG();
2941 
2942     /* Avoid infinite recursion */
2943     if (depth > 100)
2944     {
2945 	MZ_GC_UNREG();
2946 	return scheme_void;
2947     }
2948 
2949     /* Check if we run into a recursive loop.  The item must be in visited
2950      * then and we can use it again.
2951      */
2952     result = scheme_hash_get(visited, (Scheme_Object *)vim_value);
2953     MZ_GC_CHECK();
2954     if (result != NULL) /* found, do nothing */
2955 	new_value = FALSE;
2956     else if (vim_value->v_type == VAR_STRING)
2957     {
2958 	result = scheme_make_byte_string((char *)vim_value->vval.v_string);
2959 	MZ_GC_CHECK();
2960     }
2961     else if (vim_value->v_type == VAR_NUMBER)
2962     {
2963 	result = scheme_make_integer((long)vim_value->vval.v_number);
2964 	MZ_GC_CHECK();
2965     }
2966 # ifdef FEAT_FLOAT
2967     else if (vim_value->v_type == VAR_FLOAT)
2968     {
2969 	result = scheme_make_double((double)vim_value->vval.v_float);
2970 	MZ_GC_CHECK();
2971     }
2972 # endif
2973     else if (vim_value->v_type == VAR_LIST)
2974     {
2975 	list_T		*list = vim_value->vval.v_list;
2976 	listitem_T	*curr;
2977 
2978 	if (list == NULL || list->lv_first == NULL)
2979 	    result = scheme_null;
2980 	else
2981 	{
2982 	    Scheme_Object   *obj = NULL;
2983 
2984 	    MZ_GC_DECL_REG(1);
2985 	    MZ_GC_VAR_IN_REG(0, obj);
2986 	    MZ_GC_REG();
2987 
2988 	    curr = list->lv_last;
2989 	    obj = vim_to_mzscheme_impl(&curr->li_tv, depth + 1, visited);
2990 	    result = scheme_make_pair(obj, scheme_null);
2991 	    MZ_GC_CHECK();
2992 
2993 	    while (curr != list->lv_first)
2994 	    {
2995 		curr = curr->li_prev;
2996 		obj = vim_to_mzscheme_impl(&curr->li_tv, depth + 1, visited);
2997 		result = scheme_make_pair(obj, result);
2998 		MZ_GC_CHECK();
2999 	    }
3000 	}
3001 	MZ_GC_UNREG();
3002     }
3003     else if (vim_value->v_type == VAR_DICT)
3004     {
3005 	Scheme_Object	  *key = NULL;
3006 	Scheme_Object	  *obj = NULL;
3007 
3008 	MZ_GC_DECL_REG(2);
3009 	MZ_GC_VAR_IN_REG(0, key);
3010 	MZ_GC_VAR_IN_REG(1, obj);
3011 	MZ_GC_REG();
3012 
3013 	result = (Scheme_Object *)scheme_make_hash_table(SCHEME_hash_ptr);
3014 	MZ_GC_CHECK();
3015 	if (vim_value->vval.v_dict != NULL)
3016 	{
3017 	    hashtab_T	*ht = &vim_value->vval.v_dict->dv_hashtab;
3018 	    long_u	todo = ht->ht_used;
3019 	    hashitem_T	*hi;
3020 	    dictitem_T	*di;
3021 
3022 	    for (hi = ht->ht_array; todo > 0; ++hi)
3023 	    {
3024 		if (!HASHITEM_EMPTY(hi))
3025 		{
3026 		    --todo;
3027 
3028 		    di = dict_lookup(hi);
3029 		    obj = vim_to_mzscheme_impl(&di->di_tv, depth + 1, visited);
3030 		    key = scheme_make_byte_string((char *)hi->hi_key);
3031 		    MZ_GC_CHECK();
3032 		    scheme_hash_set((Scheme_Hash_Table *)result, key, obj);
3033 		    MZ_GC_CHECK();
3034 		}
3035 	    }
3036 	}
3037 	MZ_GC_UNREG();
3038     }
3039     else if (vim_value->v_type == VAR_FUNC)
3040     {
3041 	Scheme_Object *funcname = NULL;
3042 
3043 	MZ_GC_DECL_REG(1);
3044 	MZ_GC_VAR_IN_REG(0, funcname);
3045 	MZ_GC_REG();
3046 
3047 	/* FIXME: func_ref() and func_unref() are needed. */
3048 	funcname = scheme_make_byte_string((char *)vim_value->vval.v_string);
3049 	MZ_GC_CHECK();
3050 	result = scheme_make_closed_prim_w_arity(vim_funcref, funcname,
3051 		(const char *)BYTE_STRING_VALUE(funcname), 0, -1);
3052 	MZ_GC_CHECK();
3053 
3054 	MZ_GC_UNREG();
3055     }
3056     else if (vim_value->v_type == VAR_PARTIAL)
3057     {
3058 	if (vim_value->vval.v_partial == NULL)
3059 	    result = scheme_null;
3060 	else
3061 	{
3062 	    Scheme_Object *funcname = NULL;
3063 
3064 	    MZ_GC_DECL_REG(1);
3065 	    MZ_GC_VAR_IN_REG(0, funcname);
3066 	    MZ_GC_REG();
3067 
3068 	    /* FIXME: func_ref() and func_unref() are needed. */
3069 	    /* TODO: Support pt_dict and pt_argv. */
3070 	    funcname = scheme_make_byte_string(
3071 			      (char *)partial_name(vim_value->vval.v_partial));
3072 	    MZ_GC_CHECK();
3073 	    result = scheme_make_closed_prim_w_arity(vim_funcref, funcname,
3074 		    (const char *)BYTE_STRING_VALUE(funcname), 0, -1);
3075 	    MZ_GC_CHECK();
3076 
3077 	    MZ_GC_UNREG();
3078 	}
3079     }
3080     else if (vim_value->v_type == VAR_SPECIAL)
3081     {
3082 	if (vim_value->vval.v_number <= VVAL_TRUE)
3083 	    result = scheme_make_integer((long)vim_value->vval.v_number);
3084 	else
3085 	    result = scheme_null;
3086 	MZ_GC_CHECK();
3087     }
3088     else
3089     {
3090 	result = scheme_void;
3091 	new_value = FALSE;
3092     }
3093     if (new_value)
3094     {
3095 	scheme_hash_set(visited, (Scheme_Object *)vim_value, result);
3096 	MZ_GC_CHECK();
3097     }
3098     MZ_GC_UNREG();
3099     return result;
3100 }
3101 
3102     static int
3103 mzscheme_to_vim(Scheme_Object *obj, typval_T *tv)
3104 {
3105     int i, status;
3106     Scheme_Hash_Table	*visited = NULL;
3107 
3108     MZ_GC_DECL_REG(2);
3109     MZ_GC_VAR_IN_REG(0, obj);
3110     MZ_GC_VAR_IN_REG(1, visited);
3111     MZ_GC_REG();
3112 
3113     visited = scheme_make_hash_table(SCHEME_hash_ptr);
3114     MZ_GC_CHECK();
3115 
3116     status = mzscheme_to_vim_impl(obj, tv, 1, visited);
3117     for (i = 0; i < visited->size; ++i)
3118     {
3119 	/* free up remembered objects */
3120 	if (visited->vals[i] != NULL)
3121 	    free_tv((typval_T *)visited->vals[i]);
3122     }
3123 
3124     MZ_GC_UNREG();
3125     return status;
3126 }
3127     static int
3128 mzscheme_to_vim_impl(Scheme_Object *obj, typval_T *tv, int depth,
3129 	Scheme_Hash_Table *visited)
3130 {
3131     int		status = OK;
3132     typval_T	*found;
3133 
3134     MZ_GC_DECL_REG(2);
3135     MZ_GC_VAR_IN_REG(0, obj);
3136     MZ_GC_VAR_IN_REG(1, visited);
3137     MZ_GC_REG();
3138 
3139     MZ_GC_CHECK();
3140     if (depth > 100) /* limit the deepest recursion level */
3141     {
3142 	tv->v_type = VAR_NUMBER;
3143 	tv->vval.v_number = 0;
3144 	return FAIL;
3145     }
3146 
3147     found = (typval_T *)scheme_hash_get(visited, obj);
3148     if (found != NULL)
3149 	copy_tv(found, tv);
3150     else if (SCHEME_VOIDP(obj))
3151     {
3152 	tv->v_type = VAR_SPECIAL;
3153 	tv->vval.v_number = VVAL_NULL;
3154     }
3155     else if (SCHEME_INTP(obj))
3156     {
3157 	tv->v_type = VAR_NUMBER;
3158 	tv->vval.v_number = SCHEME_INT_VAL(obj);
3159     }
3160     else if (SCHEME_BOOLP(obj))
3161     {
3162 	tv->v_type = VAR_SPECIAL;
3163 	tv->vval.v_number = SCHEME_TRUEP(obj);
3164     }
3165 # ifdef FEAT_FLOAT
3166     else if (SCHEME_DBLP(obj))
3167     {
3168 	tv->v_type = VAR_FLOAT;
3169 	tv->vval.v_float = SCHEME_DBL_VAL(obj);
3170     }
3171 # endif
3172     else if (SCHEME_BYTE_STRINGP(obj))
3173     {
3174 	tv->v_type = VAR_STRING;
3175 	tv->vval.v_string = vim_strsave(BYTE_STRING_VALUE(obj));
3176     }
3177 # if MZSCHEME_VERSION_MAJOR >= 299
3178     else if (SCHEME_CHAR_STRINGP(obj))
3179     {
3180 	Scheme_Object *tmp = NULL;
3181 	MZ_GC_DECL_REG(1);
3182 	MZ_GC_VAR_IN_REG(0, tmp);
3183 	MZ_GC_REG();
3184 
3185 	tmp = scheme_char_string_to_byte_string(obj);
3186 	tv->v_type = VAR_STRING;
3187 	tv->vval.v_string = vim_strsave(BYTE_STRING_VALUE(tmp));
3188 	MZ_GC_UNREG();
3189     }
3190 #endif
3191     else if (SCHEME_VECTORP(obj) || SCHEME_NULLP(obj)
3192 	    || SCHEME_PAIRP(obj) || SCHEME_MUTABLE_PAIRP(obj))
3193     {
3194 	list_T  *list = list_alloc();
3195 	if (list == NULL)
3196 	    status = FAIL;
3197 	else
3198 	{
3199 	    int		    i;
3200 	    Scheme_Object   *curr = NULL;
3201 	    Scheme_Object   *cval = NULL;
3202 	    /* temporary var to hold current element of vectors and pairs */
3203 	    typval_T	    *v;
3204 
3205 	    MZ_GC_DECL_REG(2);
3206 	    MZ_GC_VAR_IN_REG(0, curr);
3207 	    MZ_GC_VAR_IN_REG(1, cval);
3208 	    MZ_GC_REG();
3209 
3210 	    tv->v_type = VAR_LIST;
3211 	    tv->vval.v_list = list;
3212 	    ++list->lv_refcount;
3213 
3214 	    v = (typval_T *)alloc(sizeof(typval_T));
3215 	    if (v == NULL)
3216 		status = FAIL;
3217 	    else
3218 	    {
3219 		/* add the value in advance to allow handling of self-referential
3220 		 * data structures */
3221 		typval_T    *visited_tv = (typval_T *)alloc(sizeof(typval_T));
3222 		copy_tv(tv, visited_tv);
3223 		scheme_hash_set(visited, obj, (Scheme_Object *)visited_tv);
3224 
3225 		if (SCHEME_VECTORP(obj))
3226 		{
3227 		    for (i = 0; i < SCHEME_VEC_SIZE(obj); ++i)
3228 		    {
3229 			cval = SCHEME_VEC_ELS(obj)[i];
3230 			status = mzscheme_to_vim_impl(cval, v, depth + 1, visited);
3231 			if (status == FAIL)
3232 			    break;
3233 			status = list_append_tv(list, v);
3234 			clear_tv(v);
3235 			if (status == FAIL)
3236 			    break;
3237 		    }
3238 		}
3239 		else if (SCHEME_PAIRP(obj) || SCHEME_MUTABLE_PAIRP(obj))
3240 		{
3241 		    for (curr = obj;
3242 			    SCHEME_PAIRP(curr) || SCHEME_MUTABLE_PAIRP(curr);
3243 			    curr = SCHEME_CDR(curr))
3244 		    {
3245 			cval = SCHEME_CAR(curr);
3246 			status = mzscheme_to_vim_impl(cval, v, depth + 1, visited);
3247 			if (status == FAIL)
3248 			    break;
3249 			status = list_append_tv(list, v);
3250 			clear_tv(v);
3251 			if (status == FAIL)
3252 			    break;
3253 		    }
3254 		    /* improper list not terminated with null
3255 		     * need to handle the last element */
3256 		    if (status == OK && !SCHEME_NULLP(curr))
3257 		    {
3258 			status = mzscheme_to_vim_impl(cval, v, depth + 1, visited);
3259 			if (status == OK)
3260 			{
3261 			    status = list_append_tv(list, v);
3262 			    clear_tv(v);
3263 			}
3264 		    }
3265 		}
3266 		/* nothing to do for scheme_null */
3267 		vim_free(v);
3268 	    }
3269 	    MZ_GC_UNREG();
3270 	}
3271     }
3272     else if (SCHEME_HASHTP(obj))
3273     {
3274 	int		i;
3275 	dict_T		*dict;
3276 	Scheme_Object   *key = NULL;
3277 	Scheme_Object   *val = NULL;
3278 
3279 	MZ_GC_DECL_REG(2);
3280 	MZ_GC_VAR_IN_REG(0, key);
3281 	MZ_GC_VAR_IN_REG(1, val);
3282 	MZ_GC_REG();
3283 
3284 	dict = dict_alloc();
3285 	if (dict == NULL)
3286 	    status = FAIL;
3287 	else
3288 	{
3289 	    typval_T    *visited_tv = (typval_T *)alloc(sizeof(typval_T));
3290 
3291 	    tv->v_type = VAR_DICT;
3292 	    tv->vval.v_dict = dict;
3293 	    ++dict->dv_refcount;
3294 
3295 	    copy_tv(tv, visited_tv);
3296 	    scheme_hash_set(visited, obj, (Scheme_Object *)visited_tv);
3297 
3298 	    for (i = 0; i < ((Scheme_Hash_Table *)obj)->size; ++i)
3299 	    {
3300 		if (((Scheme_Hash_Table *) obj)->vals[i] != NULL)
3301 		{
3302 		    /* generate item for `display'ed Scheme key */
3303 		    dictitem_T  *item = dictitem_alloc((char_u *)string_to_line(
3304 				((Scheme_Hash_Table *) obj)->keys[i]));
3305 		    /* convert Scheme val to Vim and add it to the dict */
3306 		    if (mzscheme_to_vim_impl(((Scheme_Hash_Table *) obj)->vals[i],
3307 				    &item->di_tv, depth + 1, visited) == FAIL
3308 			    || dict_add(dict, item) == FAIL)
3309 		    {
3310 			dictitem_free(item);
3311 			status = FAIL;
3312 			break;
3313 		    }
3314 		}
3315 
3316 	    }
3317 	}
3318 	MZ_GC_UNREG();
3319     }
3320     else
3321     {
3322 	/* `display' any other value to string */
3323 	tv->v_type = VAR_STRING;
3324 	tv->vval.v_string = (char_u *)string_to_line(obj);
3325     }
3326     MZ_GC_UNREG();
3327     return status;
3328 }
3329 
3330 /* Scheme prim procedure wrapping Vim funcref */
3331     static Scheme_Object *
3332 vim_funcref(void *name, int argc, Scheme_Object **argv)
3333 {
3334     int i;
3335     typval_T args;
3336     int status = OK;
3337     Scheme_Object *result = NULL;
3338     list_T *list = list_alloc();
3339 
3340     MZ_GC_DECL_REG(1);
3341     MZ_GC_VAR_IN_REG(0, result);
3342     MZ_GC_REG();
3343 
3344     result = scheme_void;
3345     if (list == NULL)
3346 	status = FAIL;
3347     else
3348     {
3349 	args.v_type = VAR_LIST;
3350 	args.vval.v_list = list;
3351 	++list->lv_refcount;
3352 	for (i = 0; status == OK && i < argc; ++i)
3353 	{
3354 	    typval_T *v = (typval_T *)alloc(sizeof(typval_T));
3355 	    if (v == NULL)
3356 		status = FAIL;
3357 	    else
3358 	    {
3359 		status = mzscheme_to_vim(argv[i], v);
3360 		if (status == OK)
3361 		{
3362 		    status = list_append_tv(list, v);
3363 		    clear_tv(v);
3364 		}
3365 		vim_free(v);
3366 	    }
3367 	}
3368 	if (status == OK)
3369 	{
3370 	    typval_T ret;
3371 	    ret.v_type = VAR_UNKNOWN;
3372 
3373 	    mzscheme_call_vim(BYTE_STRING_VALUE((Scheme_Object *)name), &args, &ret);
3374 	    MZ_GC_CHECK();
3375 	    result = vim_to_mzscheme(&ret);
3376 	    clear_tv(&ret);
3377 	    MZ_GC_CHECK();
3378 	}
3379     }
3380     clear_tv(&args);
3381     MZ_GC_UNREG();
3382     if (status != OK)
3383 	raise_vim_exn(_("error converting Scheme values to Vim"));
3384     else
3385 	raise_if_error();
3386     return result;
3387 }
3388 
3389     void
3390 do_mzeval(char_u *str, typval_T *rettv)
3391 {
3392     Scheme_Object	*ret = NULL;
3393 
3394     MZ_GC_DECL_REG(1);
3395     MZ_GC_VAR_IN_REG(0, ret);
3396     MZ_GC_REG();
3397 
3398     if (mzscheme_init())
3399     {
3400 	MZ_GC_UNREG();
3401 	return;
3402     }
3403 
3404     MZ_GC_CHECK();
3405     if (eval_with_exn_handling(str, do_eval, &ret) == OK)
3406 	mzscheme_to_vim(ret, rettv);
3407 
3408     MZ_GC_UNREG();
3409 }
3410 #endif
3411 
3412 /*
3413  * Check to see whether a Vim error has been reported, or a keyboard
3414  * interrupt (from vim --> got_int) has been detected.
3415  */
3416     static int
3417 vim_error_check(void)
3418 {
3419     return (got_int || did_emsg);
3420 }
3421 
3422 /*
3423  * register Scheme exn:vim
3424  */
3425     static void
3426 register_vim_exn(void)
3427 {
3428     int	nc = 0;
3429     int i;
3430     Scheme_Object   *struct_exn = NULL;
3431     Scheme_Object   *exn_name = NULL;
3432 
3433     MZ_GC_DECL_REG(2);
3434     MZ_GC_VAR_IN_REG(0, struct_exn);
3435     MZ_GC_VAR_IN_REG(1, exn_name);
3436     MZ_GC_REG();
3437 
3438     exn_name = scheme_intern_symbol("exn:vim");
3439     MZ_GC_CHECK();
3440     struct_exn = scheme_builtin_value("struct:exn");
3441     MZ_GC_CHECK();
3442 
3443     if (vim_exn == NULL)
3444 	vim_exn = scheme_make_struct_type(exn_name,
3445 		struct_exn, NULL, 0, 0, NULL, NULL
3446 #if MZSCHEME_VERSION_MAJOR >= 299
3447 		, NULL
3448 #endif
3449 		);
3450 
3451 
3452     {
3453 	Scheme_Object   **tmp = NULL;
3454 	Scheme_Object   *exn_names[5] = {NULL, NULL, NULL, NULL, NULL};
3455 	Scheme_Object   *exn_values[5] = {NULL, NULL, NULL, NULL, NULL};
3456 	MZ_GC_DECL_REG(6);
3457 	MZ_GC_ARRAY_VAR_IN_REG(0, exn_names, 5);
3458 	MZ_GC_ARRAY_VAR_IN_REG(3, exn_values, 5);
3459 	MZ_GC_REG();
3460 
3461 	tmp = scheme_make_struct_names(exn_name, scheme_null, 0, &nc);
3462 	mch_memmove(exn_names, tmp, nc * sizeof(Scheme_Object *));
3463 	MZ_GC_CHECK();
3464 
3465 	tmp = scheme_make_struct_values(vim_exn, exn_names, nc, 0);
3466 	mch_memmove(exn_values, tmp, nc * sizeof(Scheme_Object *));
3467 	MZ_GC_CHECK();
3468 
3469 	for (i = 0; i < nc; i++)
3470 	{
3471 	    scheme_add_global_symbol(exn_names[i],
3472 		    exn_values[i], environment);
3473 	    MZ_GC_CHECK();
3474 	}
3475 	MZ_GC_UNREG();
3476     }
3477     MZ_GC_UNREG();
3478 }
3479 
3480 /*
3481  * raise exn:vim, may be with additional info string
3482  */
3483     void
3484 raise_vim_exn(const char *add_info)
3485 {
3486     char	    *fmt = _("Vim error: ~a");
3487     Scheme_Object   *argv[2] = {NULL, NULL};
3488     Scheme_Object   *exn = NULL;
3489     Scheme_Object   *byte_string = NULL;
3490 
3491     MZ_GC_DECL_REG(5);
3492     MZ_GC_ARRAY_VAR_IN_REG(0, argv, 2);
3493     MZ_GC_VAR_IN_REG(3, exn);
3494     MZ_GC_VAR_IN_REG(4, byte_string);
3495     MZ_GC_REG();
3496 
3497     if (add_info != NULL)
3498     {
3499 	char		*c_string = NULL;
3500 	Scheme_Object   *info = NULL;
3501 
3502 	MZ_GC_DECL_REG(3);
3503 	MZ_GC_VAR_IN_REG(0, c_string);
3504 	MZ_GC_VAR_IN_REG(2, info);
3505 	MZ_GC_REG();
3506 
3507 	info = scheme_make_byte_string(add_info);
3508 	MZ_GC_CHECK();
3509 	c_string = scheme_format_utf8(fmt, (int)STRLEN(fmt), 1, &info, NULL);
3510 	MZ_GC_CHECK();
3511 	byte_string = scheme_make_byte_string(c_string);
3512 	MZ_GC_CHECK();
3513 	argv[0] = scheme_byte_string_to_char_string(byte_string);
3514 	SCHEME_SET_IMMUTABLE(argv[0]);
3515 	MZ_GC_UNREG();
3516     }
3517     else
3518     {
3519 	byte_string = scheme_make_byte_string(_("Vim error"));
3520 	MZ_GC_CHECK();
3521 	argv[0] = scheme_byte_string_to_char_string(byte_string);
3522 	MZ_GC_CHECK();
3523     }
3524     MZ_GC_CHECK();
3525 
3526 #if MZSCHEME_VERSION_MAJOR < 360
3527     argv[1] = scheme_current_continuation_marks();
3528     MZ_GC_CHECK();
3529 #else
3530     argv[1] = scheme_current_continuation_marks(NULL);
3531     MZ_GC_CHECK();
3532 #endif
3533 
3534     exn = scheme_make_struct_instance(vim_exn, 2, argv);
3535     MZ_GC_CHECK();
3536     scheme_raise(exn);
3537     MZ_GC_UNREG();
3538 }
3539 
3540     void
3541 raise_if_error(void)
3542 {
3543     if (vim_error_check())
3544 	raise_vim_exn(NULL);
3545 }
3546 
3547 /* get buffer:
3548  * either current
3549  * or passed as argv[argnum] with checks
3550  */
3551     static vim_mz_buffer *
3552 get_buffer_arg(const char *fname, int argnum, int argc, Scheme_Object **argv)
3553 {
3554     vim_mz_buffer *b;
3555 
3556     if (argc < argnum + 1)
3557 	return get_vim_curr_buffer();
3558     if (!SCHEME_VIMBUFFERP(argv[argnum]))
3559 	scheme_wrong_type(fname, "vim-buffer", argnum, argc, argv);
3560     b = (vim_mz_buffer *)argv[argnum];
3561     (void)get_valid_buffer(argv[argnum]);
3562     return b;
3563 }
3564 
3565 /* get window:
3566  * either current
3567  * or passed as argv[argnum] with checks
3568  */
3569     static vim_mz_window *
3570 get_window_arg(const char *fname, int argnum, int argc, Scheme_Object **argv)
3571 {
3572     vim_mz_window *w;
3573 
3574     if (argc < argnum + 1)
3575 	return get_vim_curr_window();
3576     w = (vim_mz_window *)argv[argnum];
3577     if (!SCHEME_VIMWINDOWP(argv[argnum]))
3578 	scheme_wrong_type(fname, "vim-window", argnum, argc, argv);
3579     (void)get_valid_window(argv[argnum]);
3580     return w;
3581 }
3582 
3583 /* get valid Vim buffer from Scheme_Object* */
3584 buf_T *get_valid_buffer(void *obj)
3585 {
3586     buf_T *buf = ((vim_mz_buffer *)obj)->buf;
3587 
3588     if (buf == INVALID_BUFFER_VALUE)
3589 	scheme_signal_error(_("buffer is invalid"));
3590     return buf;
3591 }
3592 
3593 /* get valid Vim window from Scheme_Object* */
3594 win_T *get_valid_window(void *obj)
3595 {
3596     win_T *win = ((vim_mz_window *)obj)->win;
3597     if (win == INVALID_WINDOW_VALUE)
3598 	scheme_signal_error(_("window is invalid"));
3599     return win;
3600 }
3601 
3602     int
3603 mzthreads_allowed(void)
3604 {
3605     return mz_threads_allow;
3606 }
3607 
3608     static int
3609 line_in_range(linenr_T lnum, buf_T *buf)
3610 {
3611     return (lnum > 0 && lnum <= buf->b_ml.ml_line_count);
3612 }
3613 
3614     static void
3615 check_line_range(linenr_T lnum, buf_T *buf)
3616 {
3617     if (!line_in_range(lnum, buf))
3618 	scheme_signal_error(_("linenr out of range"));
3619 }
3620 
3621 /*
3622  * Check if deleting lines made the cursor position invalid
3623  * (or you'll get msg from Vim about invalid linenr).
3624  * Changed the lines from "lo" to "hi" and added "extra" lines (negative if
3625  * deleted). Got from if_python.c
3626  */
3627     static void
3628 mz_fix_cursor(int lo, int hi, int extra)
3629 {
3630     if (curwin->w_cursor.lnum >= lo)
3631     {
3632 	/* Adjust the cursor position if it's in/after the changed
3633 	 * lines. */
3634 	if (curwin->w_cursor.lnum >= hi)
3635 	{
3636 	    curwin->w_cursor.lnum += extra;
3637 	    check_cursor_col();
3638 	}
3639 	else if (extra < 0)
3640 	{
3641 	    curwin->w_cursor.lnum = lo;
3642 	    check_cursor();
3643 	}
3644 	else
3645 	    check_cursor_col();
3646 	changed_cline_bef_curs();
3647     }
3648     invalidate_botline();
3649 }
3650 
3651 static Vim_Prim prims[]=
3652 {
3653     /*
3654      * Buffer-related commands
3655      */
3656     {get_buffer_line, "get-buff-line", 1, 2},
3657     {set_buffer_line, "set-buff-line", 2, 3},
3658     {get_buffer_line_list, "get-buff-line-list", 2, 3},
3659     {get_buffer_name, "get-buff-name", 0, 1},
3660     {get_buffer_num, "get-buff-num", 0, 1},
3661     {get_buffer_size, "get-buff-size", 0, 1},
3662     {set_buffer_line_list, "set-buff-line-list", 3, 4},
3663     {insert_buffer_line_list, "insert-buff-line-list", 2, 3},
3664     {get_curr_buffer, "curr-buff", 0, 0},
3665     {get_buffer_count, "buff-count", 0, 0},
3666     {get_next_buffer, "get-next-buff", 0, 1},
3667     {get_prev_buffer, "get-prev-buff", 0, 1},
3668     {mzscheme_open_buffer, "open-buff", 1, 1},
3669     {get_buffer_by_name, "get-buff-by-name", 1, 1},
3670     {get_buffer_by_num, "get-buff-by-num", 1, 1},
3671     /*
3672      * Window-related commands
3673      */
3674     {get_curr_win, "curr-win", 0, 0},
3675     {get_window_count, "win-count", 0, 0},
3676     {get_window_by_num, "get-win-by-num", 1, 1},
3677     {get_window_num, "get-win-num", 0, 1},
3678     {get_window_buffer, "get-win-buffer", 0, 1},
3679     {get_window_height, "get-win-height", 0, 1},
3680     {set_window_height, "set-win-height", 1, 2},
3681     {get_window_width, "get-win-width", 0, 1},
3682     {set_window_width, "set-win-width", 1, 2},
3683     {get_cursor, "get-cursor", 0, 1},
3684     {set_cursor, "set-cursor", 1, 2},
3685     {get_window_list, "get-win-list", 0, 1},
3686     /*
3687      * Vim-related commands
3688      */
3689     {vim_command, "command", 1, 1},
3690     {vim_eval, "eval", 1, 1},
3691     {get_range_start, "range-start", 0, 0},
3692     {get_range_end, "range-end", 0, 0},
3693     {mzscheme_beep, "beep", 0, 0},
3694     {get_option, "get-option", 1, 2},
3695     {set_option, "set-option", 1, 2},
3696     /*
3697      * small utilities
3698      */
3699     {vim_bufferp, "buff?", 1, 1},
3700     {vim_windowp, "win?", 1, 1},
3701     {vim_buffer_validp, "buff-valid?", 1, 1},
3702     {vim_window_validp, "win-valid?", 1, 1}
3703 };
3704 
3705 /* return MzScheme wrapper for curbuf */
3706     static vim_mz_buffer *
3707 get_vim_curr_buffer(void)
3708 {
3709     if (curbuf->b_mzscheme_ref == NULL)
3710 	return (vim_mz_buffer *)buffer_new(curbuf);
3711     else
3712 	return BUFFER_REF(curbuf);
3713 }
3714 
3715 /* return MzScheme wrapper for curwin */
3716     static vim_mz_window *
3717 get_vim_curr_window(void)
3718 {
3719     if (curwin->w_mzscheme_ref == NULL)
3720 	return (vim_mz_window *)window_new(curwin);
3721     else
3722 	return WINDOW_REF(curwin);
3723 }
3724 
3725     static void
3726 make_modules(void)
3727 {
3728     int		    i;
3729     Scheme_Env	    *mod = NULL;
3730     Scheme_Object   *vimext_symbol = NULL;
3731     Scheme_Object   *closed_prim = NULL;
3732 
3733     MZ_GC_DECL_REG(3);
3734     MZ_GC_VAR_IN_REG(0, mod);
3735     MZ_GC_VAR_IN_REG(1, vimext_symbol);
3736     MZ_GC_VAR_IN_REG(2, closed_prim);
3737     MZ_GC_REG();
3738 
3739     vimext_symbol = scheme_intern_symbol("vimext");
3740     MZ_GC_CHECK();
3741     mod = scheme_primitive_module(vimext_symbol, environment);
3742     MZ_GC_CHECK();
3743     /* all prims made closed so they can access their own names */
3744     for (i = 0; i < (int)(sizeof(prims)/sizeof(prims[0])); i++)
3745     {
3746 	Vim_Prim *prim = prims + i;
3747 	closed_prim = scheme_make_closed_prim_w_arity(prim->prim, prim, prim->name,
3748 			    prim->mina, prim->maxa);
3749 	scheme_add_global(prim->name, closed_prim, mod);
3750 	MZ_GC_CHECK();
3751     }
3752     scheme_finish_primitive_module(mod);
3753     MZ_GC_CHECK();
3754     MZ_GC_UNREG();
3755 }
3756 
3757 #ifdef HAVE_SANDBOX
3758 static Scheme_Object *M_write = NULL;
3759 static Scheme_Object *M_read = NULL;
3760 static Scheme_Object *M_execute = NULL;
3761 static Scheme_Object *M_delete = NULL;
3762 
3763     static void
3764 sandbox_check(void)
3765 {
3766     if (sandbox)
3767 	raise_vim_exn(_("not allowed in the Vim sandbox"));
3768 }
3769 
3770 /* security guards to force Vim's sandbox restrictions on MzScheme level */
3771     static Scheme_Object *
3772 sandbox_file_guard(int argc UNUSED, Scheme_Object **argv)
3773 {
3774     if (sandbox)
3775     {
3776 	Scheme_Object *requested_access = argv[2];
3777 
3778 	if (M_write == NULL)
3779 	{
3780 	    MZ_REGISTER_STATIC(M_write);
3781 	    M_write = scheme_intern_symbol("write");
3782 	    MZ_GC_CHECK();
3783 	}
3784 	if (M_read == NULL)
3785 	{
3786 	    MZ_REGISTER_STATIC(M_read);
3787 	    M_read = scheme_intern_symbol("read");
3788 	    MZ_GC_CHECK();
3789 	}
3790 	if (M_execute == NULL)
3791 	{
3792 	    MZ_REGISTER_STATIC(M_execute);
3793 	    M_execute = scheme_intern_symbol("execute");
3794 	    MZ_GC_CHECK();
3795 	}
3796 	if (M_delete == NULL)
3797 	{
3798 	    MZ_REGISTER_STATIC(M_delete);
3799 	    M_delete = scheme_intern_symbol("delete");
3800 	    MZ_GC_CHECK();
3801 	}
3802 
3803 	while (!SCHEME_NULLP(requested_access))
3804 	{
3805 	    Scheme_Object *item = SCHEME_CAR(requested_access);
3806 	    if (scheme_eq(item, M_write) || scheme_eq(item, M_read)
3807 		    || scheme_eq(item, M_execute) || scheme_eq(item, M_delete))
3808 	    {
3809 		raise_vim_exn(_("not allowed in the Vim sandbox"));
3810 	    }
3811 	    requested_access = SCHEME_CDR(requested_access);
3812 	}
3813     }
3814     return scheme_void;
3815 }
3816 
3817     static Scheme_Object *
3818 sandbox_network_guard(int argc UNUSED, Scheme_Object **argv UNUSED)
3819 {
3820     return scheme_void;
3821 }
3822 #endif
3823 
3824 #endif
3825