]> git.donarmstrong.com Git - lilypond.git/blob - lily/lily-guile.cc
Merge branch 'lilypond/translation'
[lilypond.git] / lily / lily-guile.cc
1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3
4   Copyright (C) 1998--2011 Jan Nieuwenhuizen <janneke@gnu.org>
5   Han-Wen Nienhuys <hanwen@xs4all.nl>
6
7   LilyPond is free software: you can redistribute it and/or modify
8   it under the terms of the GNU General Public License as published by
9   the Free Software Foundation, either version 3 of the License, or
10   (at your option) any later version.
11
12   LilyPond is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU General Public License for more details.
16
17   You should have received a copy of the GNU General Public License
18   along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "lily-guile.hh"
22
23 #include <cstdio>
24 #include <cstdlib>
25 #include <cstring> /* strdup, strchr */
26 #include <cctype>
27
28 using namespace std;
29
30 #include "dimensions.hh"
31 #include "direction.hh"
32 #include "file-path.hh"
33 #include "international.hh"
34 #include "libc-extension.hh"
35 #include "main.hh"
36 #include "misc.hh"
37 #include "offset.hh"
38 #include "pitch.hh"
39 #include "string-convert.hh"
40 #include "source-file.hh"
41 #include "version.hh"
42 #include "warn.hh"
43
44 /*
45   symbols/strings.
46  */
47 string
48 ly_scm_write_string (SCM s)
49 {
50   SCM port = scm_mkstrport (SCM_INUM0,
51                             scm_make_string (SCM_INUM0, SCM_UNDEFINED),
52                             SCM_OPN | SCM_WRTNG,
53                             "ly_write2string");
54   //  SCM write = scm_eval_3 (ly_symbol2scm ("write"), s, SCM_EOL);
55   SCM write = scm_primitive_eval (ly_symbol2scm ("write"));
56
57   // scm_apply (write, port, SCM_EOL);
58   scm_call_2 (write, s, port);
59   return ly_scm2string (scm_strport_to_string (port));
60 }
61
62 SCM
63 ly_quote_scm (SCM s)
64 {
65   return scm_list_n (ly_symbol2scm ("quote"), s, SCM_UNDEFINED);
66 }
67
68 string
69 ly_symbol2string (SCM s)
70 {
71   /*
72     Ugh. this is not very efficient.
73   */
74   SCM str = scm_symbol_to_string (s);
75   return ly_scm2string (str);
76 }
77
78 string
79 gulp_file_to_string (string fn, bool must_exist, int size)
80 {
81   string s = global_path.find (fn);
82   if (s == "")
83     {
84       if (must_exist)
85         {
86           string e = _f ("cannot find file: `%s'", fn);
87           e += " ";
88           e += _f ("(load path: `%s')", global_path.to_string ());
89           error (e);
90           /* unreachable */
91         }
92       return s;
93     }
94
95   if (be_verbose_global)
96     progress_indication ("[" + s);
97
98   vector<char> chars = gulp_file (s, size);
99   string result (&chars[0], chars.size ());
100
101   if (be_verbose_global)
102     progress_indication ("]\n");
103
104   return result;
105 }
106
107 extern "C" {
108   // maybe gdb 5.0 becomes quicker if it doesn't do fancy C++ typing?
109   void
110   ly_display_scm (SCM s)
111   {
112     scm_display (s, scm_current_output_port ());
113     scm_newline (scm_current_output_port ());
114   }
115 };
116
117 /*
118   STRINGS
119  */
120 string
121 ly_scm2string (SCM str)
122 {
123   assert (scm_is_string (str));
124   string result;
125   size_t len = scm_c_string_length (str);
126   if (len)
127     {
128       result.resize (len);
129       scm_to_locale_stringbuf (str, &result.at (0), len);
130     }
131   return result;
132 }
133
134 SCM
135 ly_string2scm (string const &str)
136 {
137   return scm_from_locale_stringn (str.c_str (),
138                                   str.length ());
139 }
140
141 char *
142 ly_scm2str0 (SCM str)
143 {
144   return scm_to_locale_string (str);
145 }
146
147 /*
148   PAIRS
149 */
150 SCM
151 index_get_cell (SCM s, Direction d)
152 {
153   assert (d);
154   return (d == LEFT) ? scm_car (s) : scm_cdr (s);
155 }
156
157 SCM
158 index_set_cell (SCM s, Direction d, SCM v)
159 {
160   if (d == LEFT)
161     scm_set_car_x (s, v);
162   else if (d == RIGHT)
163     scm_set_cdr_x (s, v);
164   return s;
165 }
166
167 bool
168 is_number_pair (SCM p)
169 {
170   return scm_is_pair (p)
171          && scm_is_number (scm_car (p)) && scm_is_number (scm_cdr (p));
172 }
173
174 unsigned int
175 ly_scm_hash (SCM s)
176 {
177   return scm_ihashv (s, ~1u);
178 }
179
180 bool
181 is_axis (SCM s)
182 {
183   if (scm_is_number (s))
184     {
185       int i = scm_to_int (s);
186       return i == 0 || i == 1;
187     }
188   return false;
189 }
190
191 bool
192 to_boolean (SCM s)
193 {
194   return scm_is_bool (s) && ly_scm2bool (s);
195 }
196
197 /*
198   DIRECTIONS
199  */
200 Direction
201 to_dir (SCM s)
202 {
203   return scm_is_integer (s) ? (Direction) scm_to_int (s) : CENTER;
204 }
205
206 Direction
207 robust_scm2dir (SCM d, Direction def)
208 {
209   if (is_direction (d))
210     def = to_dir (d);
211   return def;
212 }
213
214 bool
215 is_direction (SCM s)
216 {
217   if (scm_is_number (s))
218     {
219       int i = scm_to_int (s);
220       return i >= -1 && i <= 1;
221     }
222   return false;
223 }
224
225 /*
226   INTERVALS
227  */
228 Interval
229 ly_scm2interval (SCM p)
230 {
231   return Interval (scm_to_double (scm_car (p)), scm_to_double (scm_cdr (p)));
232 }
233
234 Drul_array<Real>
235 ly_scm2realdrul (SCM p)
236 {
237   return Drul_array<Real> (scm_to_double (scm_car (p)),
238                            scm_to_double (scm_cdr (p)));
239 }
240
241 SCM
242 ly_interval2scm (Drul_array<Real> i)
243 {
244   return scm_cons (scm_from_double (i[LEFT]), scm_from_double (i[RIGHT]));
245 }
246
247 Interval
248 robust_scm2interval (SCM k, Drul_array<Real> v)
249 {
250   Interval i;
251   i[LEFT] = v[LEFT];
252   i[RIGHT] = v[RIGHT];
253   if (is_number_pair (k))
254     i = ly_scm2interval (k);
255   return i;
256 }
257
258 Drul_array<Real>
259 robust_scm2drul (SCM k, Drul_array<Real> v)
260 {
261   if (is_number_pair (k))
262     v = ly_scm2interval (k);
263   return v;
264 }
265
266 Drul_array<bool>
267 robust_scm2booldrul (SCM k, Drul_array<bool> def)
268 {
269   if (scm_is_pair (k))
270     {
271       def[LEFT] = to_boolean (scm_car (k));
272       def[RIGHT] = to_boolean (scm_cdr (k));
273     }
274   return def;
275 }
276
277 /*
278   OFFSET
279 */
280 SCM
281 ly_offset2scm (Offset o)
282 {
283   return scm_cons (scm_from_double (o[X_AXIS]), scm_from_double (o[Y_AXIS]));
284 }
285
286 Offset
287 ly_scm2offset (SCM s)
288 {
289   return Offset (scm_to_double (scm_car (s)),
290                  scm_to_double (scm_cdr (s)));
291 }
292
293 Offset
294 robust_scm2offset (SCM k, Offset o)
295 {
296   if (is_number_pair (k))
297     o = ly_scm2offset (k);
298   return o;
299 }
300 SCM
301 ly_offsets2scm (vector<Offset> os)
302 {
303   SCM l = SCM_EOL;
304   SCM *tail = &l;
305   for (vsize i = 0; i < os.size (); i++)
306     {
307       *tail = scm_cons (ly_offset2scm (os[i]), SCM_EOL);
308       tail = SCM_CDRLOC (*tail);
309     }
310   return l;
311 }
312
313 vector<Offset>
314 ly_scm2offsets (SCM s)
315 {
316   vector<Offset> os;
317   for (; scm_is_pair (s); s = scm_cdr (s))
318     os.push_back (ly_scm2offset (scm_car (s)));
319   return os;
320 }
321
322 /*
323   ALIST
324 */
325
326 bool
327 alist_equal_p (SCM a, SCM b)
328 {
329   for (SCM s = a;
330        scm_is_pair (s); s = scm_cdr (s))
331     {
332       SCM key = scm_caar (s);
333       SCM val = scm_cdar (s);
334       SCM l = scm_assoc (key, b);
335
336       if (l == SCM_BOOL_F
337           || !ly_is_equal (scm_cdr (l), val))
338
339         return false;
340     }
341   return true;
342 }
343
344 SCM
345 ly_alist_vals (SCM alist)
346 {
347   SCM x = SCM_EOL;
348   for (SCM p = alist; scm_is_pair (p); p = scm_cdr (p))
349     x = scm_cons (scm_cdar (p), x);
350   return x;
351 }
352
353 /*
354   LISTS
355  */
356
357 /* Return I-th element, or last elt L. If I < 0, then we take the first
358    element.
359
360    PRE: length (L) > 0  */
361 SCM
362 robust_list_ref (int i, SCM l)
363 {
364   while (i-- > 0 && scm_is_pair (scm_cdr (l)))
365     l = scm_cdr (l);
366   return scm_car (l);
367 }
368
369 SCM
370 ly_deep_copy (SCM src)
371 {
372   if (scm_is_pair (src))
373     return scm_cons (ly_deep_copy (scm_car (src)), ly_deep_copy (scm_cdr (src)));
374   else if (scm_is_vector (src))
375     {
376       int len = scm_c_vector_length (src);
377       SCM nv = scm_c_make_vector (len, SCM_UNDEFINED);
378       for (int i = 0; i < len; i++)
379         {
380           SCM si = scm_from_int (i);
381           scm_vector_set_x (nv, si, ly_deep_copy (scm_vector_ref (src, si)));
382         }
383     }
384   return src;
385 }
386
387 string
388 print_scm_val (SCM val)
389 {
390   string realval = ly_scm_write_string (val);
391   if (realval.length () > 200)
392     realval = realval.substr (0, 100)
393               + "\n :\n :\n"
394               + realval.substr (realval.length () - 100);
395   return realval;
396 }
397
398 bool
399 type_check_assignment (SCM sym, SCM val, SCM type_symbol)
400 {
401   bool ok = true;
402
403   /*
404     Always succeeds.
405
406
407     TODO: should remove #f from allowed vals?
408   */
409   if (val == SCM_EOL || val == SCM_BOOL_F)
410     return ok;
411
412   if (!scm_is_symbol (sym))
413 #if 0
414     return false;
415 #else
416     /*
417       This is used for autoBeamSettings.
418
419       TODO: deprecate the use of \override and \revert for
420       autoBeamSettings?
421
422       or use a symbol autoBeamSettingS?
423     */
424     return true;
425 #endif
426
427   SCM type = scm_object_property (sym, type_symbol);
428
429   if (type != SCM_EOL && !ly_is_procedure (type))
430     {
431       warning (_f ("cannot find property type-check for `%s' (%s).",
432                    ly_symbol2string (sym).c_str (),
433                    ly_symbol2string (type_symbol).c_str ())
434                + "  " + _ ("perhaps a typing error?"));
435
436       /* Be strict when being anal :) */
437       if (do_internal_type_checking_global)
438         scm_throw (ly_symbol2scm ("ly-file-failed"), scm_list_3 (ly_symbol2scm ("typecheck"),
439                                                                  sym, val));
440
441       warning (_ ("doing assignment anyway"));
442     }
443   else
444     {
445       if (val != SCM_EOL
446           && ly_is_procedure (type)
447           && scm_call_1 (type, val) == SCM_BOOL_F)
448         {
449           ok = false;
450           SCM typefunc = ly_lily_module_constant ("type-name");
451           SCM type_name = scm_call_1 (typefunc, type);
452
453           warning (_f ("type check for `%s' failed; value `%s' must be of type `%s'",
454                        ly_symbol2string (sym).c_str (),
455                        print_scm_val (val),
456                        ly_scm2string (type_name).c_str ()));
457           progress_indication ("\n");
458         }
459     }
460   return ok;
461 }
462
463 /* some SCM abbrevs
464
465 zijn deze nou handig?
466 zijn ze er al in scheme, maar heten ze anders? */
467
468 /* Remove doubles from (sorted) list */
469 SCM
470 ly_unique (SCM list)
471 {
472   SCM unique = SCM_EOL;
473   for (SCM i = list; scm_is_pair (i); i = scm_cdr (i))
474     {
475       if (!scm_is_pair (scm_cdr (i))
476           || !ly_is_equal (scm_car (i), scm_cadr (i)))
477         unique = scm_cons (scm_car (i), unique);
478     }
479   return scm_reverse_x (unique, SCM_EOL);
480 }
481
482 /* Split list at member s, removing s.
483    Return (BEFORE . AFTER)  */
484 SCM
485 ly_split_list (SCM s, SCM list)
486 {
487   SCM before = SCM_EOL;
488   SCM after = list;
489   for (; scm_is_pair (after);)
490     {
491       SCM i = scm_car (after);
492       after = scm_cdr (after);
493       if (ly_is_equal (i, s))
494         break;
495       before = scm_cons (i, before);
496     }
497   return scm_cons (scm_reverse_x (before, SCM_EOL), after);
498 }
499
500 void
501 taint (SCM *)
502 {
503   /*
504     nop.
505   */
506 }
507
508 /*
509   display stuff without using stack
510 */
511 SCM
512 display_list (SCM s)
513 {
514   SCM p = scm_current_output_port ();
515
516   scm_puts ("(", p);
517   for (; scm_is_pair (s); s = scm_cdr (s))
518     {
519       scm_display (scm_car (s), p);
520       scm_puts (" ", p);
521     }
522   scm_puts (")", p);
523   return SCM_UNSPECIFIED;
524 }
525
526 Slice
527 int_list_to_slice (SCM l)
528 {
529   Slice s;
530   s.set_empty ();
531   for (; scm_is_pair (l); l = scm_cdr (l))
532     if (scm_is_number (scm_car (l)))
533       s.add_point (scm_to_int (scm_car (l)));
534   return s;
535 }
536
537 Real
538 robust_scm2double (SCM k, double x)
539 {
540   if (scm_is_number (k))
541     x = scm_to_double (k);
542   return x;
543 }
544
545 string
546 robust_scm2string (SCM k, string s)
547 {
548   if (scm_is_string (k))
549     s = ly_scm2string (k);
550   return s;
551 }
552
553 int
554 robust_scm2int (SCM k, int o)
555 {
556   if (scm_integer_p (k) == SCM_BOOL_T)
557     o = scm_to_int (k);
558   return o;
559 }
560
561 SCM
562 ly_rational2scm (Rational r)
563 {
564   return scm_divide (scm_from_int64 (r.numerator ()),
565                      scm_from_int64 (r.denominator ()));
566 }
567
568 Rational
569 ly_scm2rational (SCM r)
570 {
571   return Rational (scm_to_int64 (scm_numerator (r)),
572                    scm_to_int64 (scm_denominator (r)));
573 }
574
575 Rational
576 robust_scm2rational (SCM n, Rational rat)
577 {
578   if (ly_is_fraction (n))
579     return ly_scm2rational (n);
580   else
581     return rat;
582 }
583
584 SCM
585 alist_to_hashq (SCM alist)
586 {
587   int i = scm_ilength (alist);
588   if (i < 0)
589     return scm_c_make_hash_table (0);
590
591   SCM tab = scm_c_make_hash_table (i);
592   for (SCM s = alist; scm_is_pair (s); s = scm_cdr (s))
593     {
594       SCM pt = scm_cdar (s);
595       scm_hashq_set_x (tab, scm_caar (s), pt);
596     }
597   return tab;
598 }
599
600 SCM
601 ly_hash2alist (SCM tab)
602 {
603   SCM func = ly_lily_module_constant ("hash-table->alist");
604   return scm_call_1 (func, tab);
605 }
606
607 /*
608   C++ interfacing.
609  */
610
611 string
612 mangle_cxx_identifier (string cxx_id)
613 {
614   if (cxx_id.substr (0, 3) == "ly_")
615     cxx_id = cxx_id.replace (0, 3, "ly:");
616   else
617     {
618       cxx_id = String_convert::to_lower (cxx_id);
619       cxx_id = "ly:" + cxx_id;
620     }
621   if (cxx_id.substr (cxx_id.length () - 2) == "_p")
622     cxx_id = cxx_id.replace (cxx_id.length () - 2, 2, "?");
623   else if (cxx_id.substr (cxx_id.length () - 2) == "_x")
624     cxx_id = cxx_id.replace (cxx_id.length () - 2, 2, "!");
625
626   replace_all (&cxx_id, "_less?", "<?");
627   replace_all (&cxx_id, "_2_", "->");
628   replace_all (&cxx_id, "__", "::");
629   replace_all (&cxx_id, '_', '-');
630
631   return cxx_id;
632 }
633
634 SCM
635 ly_string_array_to_scm (vector<string> a)
636 {
637   SCM s = SCM_EOL;
638   for (vsize i = a.size (); i; i--)
639     s = scm_cons (ly_symbol2scm (a[i - 1].c_str ()), s);
640   return s;
641 }
642
643 /* SYMBOLS is a whitespace separated list.  */
644 SCM
645 parse_symbol_list (char const *symbols)
646 {
647   while (isspace (*symbols))
648     symbols++;
649   string s = symbols;
650   replace_all (&s, '\n', ' ');
651   replace_all (&s, '\t', ' ');
652   replace_all (&s, "  ", " ");
653   return ly_string_array_to_scm (string_split (s, ' '));
654 }
655
656 /* GDB debugging. */
657 struct ly_t_double_cell
658 {
659   SCM a;
660   SCM b;
661   SCM c;
662   SCM d;
663 };
664
665 /* inserts at front, removing duplicates */
666 SCM ly_assoc_prepend_x (SCM alist, SCM key, SCM val)
667 {
668   return scm_acons (key, val, scm_assoc_remove_x (alist, key));
669 }
670