]> git.donarmstrong.com Git - lilypond.git/blob - lily/lily-guile.cc
release: 1.3.107
[lilypond.git] / lily / lily-guile.cc
1 /*
2   lily-guile.cc -- implement assorted guile functions
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 1998--2000 Jan Nieuwenhuizen <janneke@gnu.org>
7
8   Han-Wen Nienhuys <hanwen@cs.uu.nl>
9 */
10
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <math.h>               // isinf
15
16 #include "libc-extension.hh"
17 #include "lily-guile.hh"
18 #include "main.hh"
19 #include "simple-file-storage.hh"
20 #include "file-path.hh"
21 #include "debug.hh"
22 #include "direction.hh"
23 #include "offset.hh"
24 #include "interval.hh"
25
26 SCM
27 ly_str02scm (char const*c)
28 {
29   // this all really sucks, guile should take char const* arguments!
30   return gh_str02scm ((char*)c);
31 }
32
33
34
35 /*
36   Pass string to scm parser, evaluate one expression.
37   Return result value and #chars read.
38
39   Thanks to Gary Houston <ghouston@freewire.co.uk>
40
41   Need guile-1.3.4 (>1.3 anyway) for ftell on str ports -- jcn
42 */
43 SCM
44 ly_parse_scm (char const* s, int* n)
45 {
46   SCM str = gh_str02scm ((char*)s);
47   SCM port = scm_mkstrport (SCM_INUM0, str, SCM_OPN | SCM_RDNG,
48                             "ly_eval_scm_0str");
49   SCM from = scm_ftell (port);
50
51   SCM form;
52   SCM answer = SCM_UNSPECIFIED;
53
54   /* Read expression from port */
55   if (!SCM_EOF_OBJECT_P (form = scm_read (port)))
56     answer = scm_eval_3 (form, 1, SCM_EOL); // guh?
57
58   /*
59    After parsing
60
61        (begin (foo 1 2))
62
63    all seems fine, but after parsing
64
65        (foo 1 2)
66
67    read_buf has been advanced to read_pos - 1,
68    so that scm_ftell returns 1, instead of #parsed chars
69    */
70   
71   /*
72     urg: reset read_buf for scm_ftell
73     shouldn't scm_read () do this for us?
74   */
75   scm_fill_input (port);
76   SCM to = scm_ftell (port);
77   *n = gh_scm2int (to) - gh_scm2int (from);
78
79   /* Don't close the port here; if we re-enter this function via a
80      continuation, then the next time we enter it, we'll get an error.
81      It's a string port anyway, so there's no advantage to closing it
82      early.
83
84      scm_close_port (port);
85   */
86
87   return answer;
88 }
89
90 SCM
91 ly_quote_scm (SCM s)
92 {
93   return gh_list (ly_symbol2scm ("quote"), s, SCM_UNDEFINED);
94 }
95
96
97 SCM
98 ly_symbol2scm(const char *s)
99 {
100   return gh_symbol2scm ((char *)s);
101 }
102
103
104 String
105 ly_symbol2string (SCM s)
106 {
107   assert (gh_symbol_p (s));
108   return String((Byte*)SCM_CHARS (s), (int) SCM_LENGTH(s));
109 }
110
111
112 String
113 gulp_file_to_string (String fn)
114 {
115   String s = global_path.find (fn);
116   if (s == "")
117     {
118       String e = _f ("can't find file: `%s'", fn);
119       e += " ";
120       e += _f ("(load path: `%s')", global_path.str ());
121       error (e);
122     }
123   else if (verbose_global_b)
124     progress_indication ("[" + s );
125
126
127   Simple_file_storage f(s);
128   String result (f.ch_C());
129   if (verbose_global_b)
130     progress_indication ("]");
131   return result;
132 }
133
134 SCM
135 ly_gulp_file (SCM fn)
136 {
137   return ly_str02scm (gulp_file_to_string (ly_scm2string (fn)).ch_C());
138 }
139
140
141 /**
142    Read a file, and shove it down GUILE.  GUILE also has file read
143    functions, but you can't fiddle with the path of those.
144  */
145 void
146 read_lily_scm_file (String fn)
147 {
148   gh_eval_str ((char *) gulp_file_to_string (fn).ch_C());
149 }
150
151 extern "C" {
152   // maybe gdb 5.0 becomes quicker if it doesn't do fancy C++ typing?
153 void
154 ly_display_scm (SCM s)
155 {
156   gh_display (s);
157   gh_newline ();
158 }
159 };
160
161 String
162 ly_scm2string (SCM s)
163 {
164   assert (gh_string_p (s));
165   int len; 
166   char * p = gh_scm2newstr (s , &len);
167   
168   String r (p);
169
170   free (p);
171   return r;
172 }
173
174 SCM
175 index_cell (SCM s, Direction d)
176 {
177   assert (d);
178   return (d == LEFT) ? gh_car  (s) : gh_cdr (s);
179 }
180
181 SCM
182 index_set_cell (SCM s, Direction d, SCM v)
183 {
184   if (d == LEFT)
185     gh_set_car_x (s, v);
186   else if (d == RIGHT)
187     gh_set_cdr_x (s, v);
188   return s;
189 }
190   
191 SCM
192 ly_warning (SCM str)
193 {
194   assert (gh_string_p (str));
195   warning ("lily-guile: " + ly_scm2string (str));
196   return SCM_BOOL_T;
197 }
198
199 SCM
200 ly_isdir_p (SCM s)
201 {
202   if (gh_number_p (s))
203     {
204       int i = gh_scm2int (s);
205       return (i>= -1 && i <= 1)  ? SCM_BOOL_T : SCM_BOOL_F; 
206     }
207   return SCM_BOOL_F;
208 }
209
210
211
212 typedef void (*Void_fptr)();
213 Array<Void_fptr> *scm_init_funcs_;
214
215 void add_scm_init_func (void (*f)())
216 {
217   if (!scm_init_funcs_)
218     scm_init_funcs_ = new Array<Void_fptr>;
219
220   scm_init_funcs_->push (f);
221 }
222 extern  void init_cxx_function_smobs();
223
224 void
225 init_lily_guile ()
226 {
227   init_cxx_function_smobs();
228   for (int i=scm_init_funcs_->size() ; i--;)
229     (scm_init_funcs_->elem (i)) ();
230 }
231
232 unsigned int ly_scm_hash (SCM s)
233 {
234   return scm_ihashv (s, ~1u);
235 }
236
237
238
239 bool
240 isdir_b (SCM s)
241 {
242   if (gh_number_p (s))
243     {
244       int i = gh_scm2int (s);
245       return i>= -1 && i <= 1; 
246     }
247   return false;
248 }
249
250 Direction
251 to_dir (SCM s)
252 {
253   return (Direction) gh_scm2int (s);
254 }
255
256 Interval
257 ly_scm2interval (SCM p)
258 {
259   return  Interval (gh_scm2double (gh_car (p)),
260                     gh_scm2double (gh_cdr (p)));
261 }
262
263 SCM
264 ly_interval2scm (Interval i)
265 {
266   return gh_cons (gh_double2scm (i[LEFT]),
267                   gh_double2scm (i[RIGHT]));
268 }
269
270
271 bool
272 to_boolean (SCM s)
273 {
274   return gh_boolean_p (s) && gh_scm2bool (s);
275 }
276
277 /*
278   Appendable list L: the cdr contains the list, the car the last cons
279   in the list.
280  */
281 SCM
282 appendable_list ()
283 {
284   SCM s = gh_cons (SCM_EOL, SCM_EOL);
285   gh_set_car_x (s, s);
286   
287   return s;
288 }
289
290 void
291 appendable_list_append (SCM l, SCM elt)
292 {
293   SCM newcons = gh_cons (elt, SCM_EOL);
294   
295   gh_set_cdr_x (gh_car (l), newcons);      
296   gh_set_car_x (l, newcons);
297 }
298
299
300 SCM
301 ly_offset2scm (Offset o)
302 {
303   return gh_cons (gh_double2scm (o[X_AXIS]), gh_double2scm(o[Y_AXIS]));
304 }
305
306 Offset
307 ly_scm2offset (SCM s)
308 {
309   return Offset (gh_scm2double (gh_car (s)),
310                  gh_scm2double (gh_cdr (s)));
311 }
312
313 SCM
314 ly_type (SCM exp)
315 {
316   char const  * cp = "unknown";
317   if (gh_number_p (exp))
318     {
319       cp = "number";
320     }
321   else if (gh_string_p (exp))
322     {
323       cp = "string";
324     }
325   else if (gh_procedure_p (exp))
326     {
327       cp = "procedure";
328     }
329   else if (gh_boolean_p (exp))
330     {
331       cp = "boolean";
332     }
333   else if (gh_pair_p (exp))
334     {
335       cp = "list";
336     }
337
338   return ly_str02scm (cp);
339 }
340
341 /*
342   convert without too many decimals, and leave  a space at the end.
343  */
344    
345    
346 SCM
347 ly_number2string (SCM s)
348 {
349   assert (gh_number_p (s));
350
351   char str[400];                        // ugh.
352
353   if (scm_integer_p (s) == SCM_BOOL_F)
354     {
355       Real r (gh_scm2double (s));
356
357       if (isinf (r) || isnan (r))
358         {
359           programming_error ("Infinity or NaN encountered while converting Real number; setting to zero.");
360           r = 0.0;
361         }
362
363       sprintf (str, "%8.4f ", r);
364     }
365   else
366     {
367       sprintf (str, "%d ", gh_scm2int (s));
368     }
369
370   return gh_str02scm (str);
371 }
372
373 /*
374   Undef this to see if GUILE GC is causing too many swaps.
375  */
376
377 // #define TEST_GC
378
379 #ifdef TEST_GC
380 #include <libguile/gc.h>
381
382 static void *
383 greet_sweep (void *dummy1, void *dummy2, void *dummy3)
384 {
385    fprintf(stderr, "entering sweep\n");
386 }
387
388 static void *
389 wave_sweep_goodbye (void *dummy1, void *dummy2, void *dummy3)
390 {
391    fprintf(stderr, "leaving sweep\n");
392 }
393 #endif
394
395
396 #include "version.hh"
397 SCM
398 ly_version ()
399 {
400   char const* vs =  "\'(" MAJOR_VERSION " " MINOR_VERSION " "  PATCH_LEVEL " " MY_PATCH_LEVEL ")" ;
401
402   
403   return gh_eval_str ((char*)vs);
404 }
405
406 static void
407 init_functions ()
408 {
409   scm_make_gsubr ("ly-warn", 1, 0, 0, (Scheme_function_unknown)ly_warning);
410   scm_make_gsubr ("ly-version", 0, 0, 0, (Scheme_function_unknown)ly_warning);  
411   scm_make_gsubr ("ly-gulp-file", 1,0, 0, (Scheme_function_unknown)ly_gulp_file);
412   scm_make_gsubr ("dir?", 1,0, 0, (Scheme_function_unknown)ly_isdir_p);
413
414   scm_make_gsubr ("ly-number->string", 1, 0,0, (Scheme_function_unknown) ly_number2string);
415
416
417 #ifdef TEST_GC 
418   scm_c_hook_add (&scm_before_mark_c_hook, greet_sweep, 0, 0);
419   scm_c_hook_add (&scm_before_sweep_c_hook, wave_sweep_goodbye, 0, 0);
420 #endif
421 }
422
423 ADD_SCM_INIT_FUNC(funcs, init_functions);
424
425 SCM
426 ly_deep_copy (SCM l)
427 {
428   if (gh_pair_p (l))
429     {
430       return gh_cons (ly_deep_copy (gh_car (l)), ly_deep_copy (gh_cdr (l)));
431     }
432   else
433     return l;
434 }
435
436
437
438
439 SCM
440 ly_assoc_chain (SCM key, SCM achain)
441 {
442   if (gh_pair_p (achain))
443     {
444       SCM handle = scm_assoc (key, gh_car (achain));
445       if (gh_pair_p (handle))
446         return handle;
447       else
448         return ly_assoc_chain (key, gh_cdr (achain));
449     }
450   else
451     return SCM_BOOL_F;
452 }