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