2 lily-guile.cc -- implement assorted guile functions
4 source file of the GNU LilyPond music typesetter
6 (c) 1998--2001 Jan Nieuwenhuizen <janneke@gnu.org>
8 Han-Wen Nienhuys <hanwen@cs.uu.nl>
14 #include <math.h> // isinf
16 #include "libc-extension.hh"
17 #include "lily-guile.hh"
19 #include "simple-file-storage.hh"
20 #include "file-path.hh"
22 #include "direction.hh"
24 #include "interval.hh"
29 return gh_car (scm_last_pair (list
));
33 ly_str02scm (char const*c
)
35 // this all really sucks, guile should take char const* arguments!
36 return gh_str02scm ((char*)c
);
43 SCM port
= scm_mkstrport (SCM_INUM0
,
44 scm_make_string (SCM_INUM0
, SCM_UNDEFINED
),
47 // SCM write = scm_eval_3 (ly_symbol2scm ("write"), s, SCM_EOL);
48 SCM write
= scm_eval2 (ly_symbol2scm ("write"), SCM_EOL
);
50 // scm_apply (write, port, SCM_EOL);
51 gh_call2 (write
, s
, port
);
52 return scm_strport_to_string (port
);
57 Pass string to scm parser, evaluate one expression.
58 Return result value and #chars read.
60 Thanks to Gary Houston <ghouston@freewire.co.uk>
62 Need guile-1.3.4 (>1.3 anyway) for ftell on str ports -- jcn
65 ly_parse_scm (char const* s
, int* n
)
67 SCM str
= ly_str02scm (s
);
68 SCM port
= scm_mkstrport (SCM_INUM0
, str
, SCM_OPN
| SCM_RDNG
,
70 SCM from
= scm_ftell (port
);
73 SCM answer
= SCM_UNSPECIFIED
;
75 /* Read expression from port */
76 if (!SCM_EOF_OBJECT_P (form
= scm_read (port
)))
77 answer
= scm_eval_3 (form
, 1, SCM_EOL
); // guh?
84 all seems fine, but after parsing
88 read_buf has been advanced to read_pos - 1,
89 so that scm_ftell returns 1, instead of #parsed chars
93 urg: reset read_buf for scm_ftell
94 shouldn't scm_read () do this for us?
96 scm_fill_input (port
);
97 SCM to
= scm_ftell (port
);
98 *n
= gh_scm2int (to
) - gh_scm2int (from
);
100 /* Don't close the port here; if we re-enter this function via a
101 continuation, then the next time we enter it, we'll get an error.
102 It's a string port anyway, so there's no advantage to closing it
105 scm_close_port (port);
114 return gh_list (ly_symbol2scm ("quote"), s
, SCM_UNDEFINED
);
119 ly_symbol2scm (const char *s
)
121 return gh_symbol2scm ((char *)s
);
126 ly_symbol2string (SCM s
)
128 assert (gh_symbol_p (s
));
129 return String ((Byte
*)SCM_CHARS (s
), (int) SCM_LENGTH (s
));
134 gulp_file_to_string (String fn
)
136 String s
= global_path
.find (fn
);
139 String e
= _f ("can't find file: `%s'", fn
);
141 e
+= _f ("(load path: `%s')", global_path
.str ());
144 else if (verbose_global_b
)
145 progress_indication ("[" + s
);
148 Simple_file_storage
f (s
);
149 String
result (f
.ch_C ());
150 if (verbose_global_b
)
151 progress_indication ("]");
156 ly_gulp_file (SCM fn
)
158 return ly_str02scm (gulp_file_to_string (ly_scm2string (fn
)).ch_C ());
163 Read a file, and shove it down GUILE. GUILE also has file read
164 functions, but you can't fiddle with the path of those.
167 read_lily_scm_file (String fn
)
169 gh_eval_str ((char *) gulp_file_to_string (fn
).ch_C ());
173 // maybe gdb 5.0 becomes quicker if it doesn't do fancy C++ typing?
175 ly_display_scm (SCM s
)
183 ly_scm2string (SCM s
)
185 assert (gh_string_p (s
));
187 char * p
= gh_scm2newstr (s
, &len
);
196 index_cell (SCM s
, Direction d
)
199 return (d
== LEFT
) ? gh_car (s
) : gh_cdr (s
);
203 index_set_cell (SCM s
, Direction d
, SCM v
)
215 assert (gh_string_p (str
));
216 warning ("lily-guile: " + ly_scm2string (str
));
225 int i
= gh_scm2int (s
);
226 return (i
>= -1 && i
<= 1) ? SCM_BOOL_T
: SCM_BOOL_F
;
232 ly_number_pair_p (SCM p
)
234 return gh_pair_p (p
) && gh_number_p (gh_car (p
)) && gh_number_p (gh_cdr (p
));
240 return gh_number_p (a
) && (gh_scm2int (a
) == 0 || gh_scm2int (a
) == 1);
243 typedef void (*Void_fptr
) ();
244 Array
<Void_fptr
> *scm_init_funcs_
;
246 void add_scm_init_func (void (*f
) ())
248 if (!scm_init_funcs_
)
249 scm_init_funcs_
= new Array
<Void_fptr
>;
251 scm_init_funcs_
->push (f
);
253 extern void init_cxx_function_smobs ();
258 init_cxx_function_smobs ();
259 for (int i
=scm_init_funcs_
->size () ; i
--;)
260 (scm_init_funcs_
->elem (i
)) ();
263 unsigned int ly_scm_hash (SCM s
)
265 return scm_ihashv (s
, ~1u);
275 int i
= gh_scm2int (s
);
276 return i
>= -1 && i
<= 1;
287 int i
= gh_scm2int (s
);
288 return i
== 0 || i
== 1;
297 return (Direction
) gh_scm2int (s
);
301 ly_scm2interval (SCM p
)
303 return Interval (gh_scm2double (gh_car (p
)),
304 gh_scm2double (gh_cdr (p
)));
308 ly_interval2scm (Interval i
)
310 return gh_cons (gh_double2scm (i
[LEFT
]),
311 gh_double2scm (i
[RIGHT
]));
320 return gh_boolean_p (s
) && gh_scm2bool (s
);
324 Appendable list L: the cdr contains the list, the car the last cons
330 SCM s
= gh_cons (SCM_EOL
, SCM_EOL
);
337 appendable_list_append (SCM l
, SCM elt
)
339 SCM newcons
= gh_cons (elt
, SCM_EOL
);
341 gh_set_cdr_x (gh_car (l
), newcons
);
342 gh_set_car_x (l
, newcons
);
347 ly_offset2scm (Offset o
)
349 return gh_cons (gh_double2scm (o
[X_AXIS
]), gh_double2scm (o
[Y_AXIS
]));
353 ly_scm2offset (SCM s
)
355 return Offset (gh_scm2double (gh_car (s
)),
356 gh_scm2double (gh_cdr (s
)));
362 char const * cp
= "unknown";
363 if (gh_number_p (exp
))
367 else if (gh_string_p (exp
))
371 else if (gh_procedure_p (exp
))
375 else if (gh_boolean_p (exp
))
379 else if (gh_pair_p (exp
))
384 return ly_str02scm (cp
);
388 convert without too many decimals, and leave a space at the end.
393 ly_number2string (SCM s
)
395 assert (gh_number_p (s
));
397 char str
[400]; // ugh.
399 if (scm_integer_p (s
) == SCM_BOOL_F
)
401 Real
r (gh_scm2double (s
));
403 if (isinf (r
) || isnan (r
))
405 programming_error ("Infinity or NaN encountered while converting Real number; setting to zero.");
409 sprintf (str
, "%8.4f ", r
);
413 sprintf (str
, "%d ", gh_scm2int (s
));
416 return ly_str02scm (str
);
420 Undef this to see if GUILE GC is causing too many swaps.
426 #include <libguile/gc.h>
429 greet_sweep (void *dummy1
, void *dummy2
, void *dummy3
)
431 fprintf (stderr
, "entering sweep\n");
435 wave_sweep_goodbye (void *dummy1
, void *dummy2
, void *dummy3
)
437 fprintf (stderr
, "leaving sweep\n");
442 #include "version.hh"
446 char const* vs
= "\' (" MAJOR_VERSION
" " MINOR_VERSION
" " PATCH_LEVEL
" " MY_PATCH_LEVEL
")" ;
449 return gh_eval_str ((char*)vs
);
455 scm_make_gsubr ("ly-warn", 1, 0, 0, (Scheme_function_unknown
)ly_warning
);
456 scm_make_gsubr ("ly-version", 0, 0, 0, (Scheme_function_unknown
)ly_version
);
457 scm_make_gsubr ("ly-gulp-file", 1,0, 0, (Scheme_function_unknown
)ly_gulp_file
);
458 scm_make_gsubr ("dir?", 1,0, 0, (Scheme_function_unknown
)ly_isdir_p
);
460 scm_make_gsubr ("ly-number->string", 1, 0,0, (Scheme_function_unknown
) ly_number2string
);
464 scm_c_hook_add (&scm_before_mark_c_hook
, greet_sweep
, 0, 0);
465 scm_c_hook_add (&scm_before_sweep_c_hook
, wave_sweep_goodbye
, 0, 0);
469 ADD_SCM_INIT_FUNC (funcs
, init_functions
);
476 return gh_cons (ly_deep_copy (gh_car (l
)), ly_deep_copy (gh_cdr (l
)));
486 ly_assoc_chain (SCM key
, SCM achain
)
488 if (gh_pair_p (achain
))
490 SCM handle
= scm_assoc (key
, gh_car (achain
));
491 if (gh_pair_p (handle
))
494 return ly_assoc_chain (key
, gh_cdr (achain
));