]> git.donarmstrong.com Git - lilypond.git/blob - lily/general-scheme.cc
Web-ja: update introduction
[lilypond.git] / lily / general-scheme.cc
1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3
4   Copyright (C) 1998--2015 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 "config.hh"
22
23 #include <cstdio>
24 #include <ctype.h>
25 #include <cstring>  /* memset */
26 #include <glib.h>
27 using namespace std;
28
29 #include "dimensions.hh"
30 #include "file-name.hh"
31 #include "file-path.hh"
32 #include "international.hh"
33 #include "libc-extension.hh"
34 #include "lily-guile.hh"
35 #include "main.hh"
36 #include "misc.hh"
37 #include "program-option.hh"
38 #include "relocate.hh"
39 #include "string-convert.hh"
40 #include "version.hh"
41 #include "warn.hh"
42
43 /* Declaration of log function(s) */
44 SCM ly_progress (SCM, SCM);
45
46 LY_DEFINE (ly_start_environment, "ly:start-environment",
47            0, 0, 0, (),
48            "Return the environment (a list of strings) that was in"
49            " effect at program start.")
50 {
51   SCM l = SCM_EOL;
52   SCM *tail = &l;
53
54   for (vsize i = 0; i < start_environment_global.size (); i++)
55     {
56       *tail = scm_cons (ly_string2scm (start_environment_global[i]),
57                         SCM_EOL);
58       tail = SCM_CDRLOC (*tail);
59     }
60
61   return l;
62 }
63
64 LY_DEFINE (ly_find_file, "ly:find-file",
65            1, 0, 0, (SCM name),
66            "Return the absolute file name of @var{name},"
67            " or @code{#f} if not found.")
68 {
69   LY_ASSERT_TYPE (scm_is_string, name, 1);
70
71   string nm = ly_scm2string (name);
72   string file_name = global_path.find (nm);
73   if (file_name.empty ())
74     return SCM_BOOL_F;
75
76   return ly_string2scm (file_name);
77 }
78
79 /*
80   Ugh. Gulped file is copied twice. (maybe thrice if you count stdio
81   buffering.)
82 */
83 LY_DEFINE (ly_gulp_file, "ly:gulp-file",
84            1, 1, 0, (SCM name, SCM size),
85            "Read @var{size} characters from the file @var{name},"
86            " and return its contents in a string."
87            "  If @var{size} is undefined, the entire file is read."
88            "  The file is looked up using the search path.")
89 {
90   LY_ASSERT_TYPE (scm_is_string, name, 1);
91   int sz = INT_MAX;
92   if (!SCM_UNBNDP (size))
93     {
94       LY_ASSERT_TYPE (scm_is_number, size, 2);
95       sz = scm_to_int (size);
96     }
97
98   string contents = gulp_file_to_string (ly_scm2string (name), true, sz);
99   return scm_from_latin1_stringn (contents.c_str (), contents.length ());
100 }
101
102 LY_DEFINE (ly_dir_p, "ly:dir?",
103            1, 0, 0, (SCM s),
104            "Is @var{s} a direction?  Valid directions are @w{@code{-1}},"
105            " @code{0}, or@tie{}@code{1}, where @w{@code{-1}} represents"
106            " left or down, @code{1}@tie{}represents right or up, and @code{0}"
107            " represents a neutral direction.")
108 {
109   if (scm_is_integer (s))
110     {
111       int i = scm_to_int (s);
112       return (i >= -1 && i <= 1) ? SCM_BOOL_T : SCM_BOOL_F;
113     }
114   return SCM_BOOL_F;
115 }
116
117 LY_DEFINE (ly_assoc_get, "ly:assoc-get",
118            2, 2, 0,
119            (SCM key, SCM alist, SCM default_value, SCM strict_checking),
120            "Return value if @var{key} in @var{alist}, else @var{default-value}"
121            " (or @code{#f} if not specified).  If @var{strict-checking} is set"
122            " to @code{#t} and @var{key} is not in @var{alist}, a programming_error"
123            " is output.")
124 {
125   LY_ASSERT_TYPE (ly_cheap_is_list, alist, 2);
126
127   SCM handle = scm_assoc (key, alist);
128   if (scm_is_pair (handle))
129     return scm_cdr (handle);
130
131   if (SCM_UNBNDP (default_value))
132     default_value = SCM_BOOL_F;
133
134   if (to_boolean (strict_checking))
135     {
136       string key_string = ly_scm2string
137                           (scm_object_to_string (key, SCM_UNDEFINED));
138       string default_value_string = ly_scm2string
139                                     (scm_object_to_string (default_value,
140                                                            SCM_UNDEFINED));
141       programming_error ("Cannot find key `"
142                          + key_string
143                          + "' in alist, setting to `"
144                          + default_value_string + "'.");
145     }
146
147   return default_value;
148 }
149
150 LY_DEFINE (ly_string_substitute, "ly:string-substitute",
151            3, 0, 0, (SCM a, SCM b, SCM s),
152            "Replace string@tie{}@var{a} by string@tie{}@var{b} in"
153            " string@tie{}@var{s}.")
154 {
155   LY_ASSERT_TYPE (scm_is_string, s, 1);
156   LY_ASSERT_TYPE (scm_is_string, b, 2);
157   LY_ASSERT_TYPE (scm_is_string, s, 3);
158
159   string ss = ly_scm2string (s);
160   replace_all (&ss, ly_scm2string (a),
161                ly_scm2string (b));
162
163   return ly_string2scm (ss);
164 }
165
166 bool
167 is_not_escape_character (Byte c)
168 {
169   switch (c)
170     {
171     case '-':
172     case '.':
173     case '/':
174     case '0'...'9':
175     case ':':
176     case 'A'...'Z':
177     case '_':
178     case 'a'...'z':
179       return true;
180     }
181
182   return false;
183 }
184
185 LY_DEFINE (ly_string_percent_encode, "ly:string-percent-encode",
186            1, 0, 0, (SCM str),
187            "Encode all characters in string @var{str} with hexadecimal"
188            " percent escape sequences, with the following exceptions:"
189            " characters @w{@code{-},} @code{.}, @code{/}, and @code{_}; and"
190            " characters in ranges @code{0-9}, @code{A-Z}, and @code{a-z}.")
191 {
192   LY_ASSERT_TYPE (scm_is_string, str, 1);
193
194   string orig_str = ly_scm2string (str);
195   string new_str = "";
196
197   vsize i = 0;
198   vsize n = orig_str.size ();
199
200   while (i < n)
201     {
202       Byte cur = orig_str[i];
203
204       if (is_not_escape_character (cur))
205         new_str += cur;
206       else
207         {
208           new_str += '%';
209           new_str += String_convert::bin2hex (cur);
210         }
211
212       i++;
213     }
214
215   return ly_string2scm (new_str);
216 }
217
218 LY_DEFINE (ly_number_2_string, "ly:number->string",
219            1, 0, 0, (SCM s),
220            "Convert @var{s} to a string without generating many decimals.")
221 {
222   LY_ASSERT_TYPE (scm_is_number, s, 1);
223
224   char str[400];                        // ugh.
225
226   if (scm_is_false (scm_exact_p (s)))
227     {
228       Real r (scm_to_double (s));
229       if (isinf (r) || isnan (r))
230         {
231           programming_error ("infinity or NaN encountered while converting Real number, "
232                              "setting to zero");
233
234           r = 0.0;
235         }
236
237       snprintf (str, sizeof (str), "%.4f", r);
238     }
239   else
240     snprintf (str, sizeof (str), "%d", int (scm_to_int (s)));
241
242   return scm_from_ascii_string (str);
243 }
244
245 LY_DEFINE (ly_version, "ly:version", 0, 0, 0, (),
246            "Return the current lilypond version as a list, e.g.,"
247            " @code{(1 3 127 uu1)}.")
248 {
249   char const *vs = "\'(" MAJOR_VERSION " " MINOR_VERSION " " PATCH_LEVEL " " MY_PATCH_LEVEL ")";
250
251   return scm_c_eval_string ((char *)vs);
252 }
253
254 LY_DEFINE (ly_unit, "ly:unit", 0, 0, 0, (),
255            "Return the unit used for lengths as a string.")
256 {
257   return scm_from_ascii_string (INTERNAL_UNIT);
258 }
259
260 LY_DEFINE (ly_dimension_p, "ly:dimension?", 1, 0, 0, (SCM d),
261            "Return @var{d} as a number.  Used to distinguish length"
262            " variables from normal numbers.")
263 {
264   return scm_number_p (d);
265 }
266
267 /*
268   Debugging mem leaks:
269 */
270 LY_DEFINE (ly_protects, "ly:protects",
271            0, 0, 0, (),
272            "Return hash of protected objects.")
273 {
274   //scm_protects is available only in Guile versions before 2.1.
275 #if SCM_MAJOR_VERSION < 2 || SCM_MAJOR_VERSION == 2 && SCM_MINOR_VERSION < 1
276   return scm_protects;
277 #else
278   return programming_error ("ly:protects is not supported in Guile 2.1");
279 #endif
280 }
281
282 LY_DEFINE (ly_gettext, "ly:gettext",
283            1, 0, 0, (SCM original),
284            "A Scheme wrapper function for @code{gettext}.")
285 {
286   LY_ASSERT_TYPE (scm_is_string, original, 1);
287   return ly_string2scm (_ (ly_scm2string (original).c_str ()));
288 }
289
290 LY_DEFINE (ly_output_formats, "ly:output-formats",
291            0, 0, 0, (),
292            "Formats passed to @option{--format} as a list of strings,"
293            " used for the output.")
294 {
295   vector<string> output_formats = string_split (output_format_global, ',');
296
297   SCM lst = SCM_EOL;
298   int output_formats_count = output_formats.size ();
299   for (int i = 0; i < output_formats_count; i++)
300     lst = scm_cons (ly_string2scm (output_formats[i]), lst);
301
302   return lst;
303 }
304
305 LY_DEFINE (ly_bigpdfs, "ly:bigpdfs",
306            0, 0, 0, (),
307            "Return true if the command line includes the @option{--bigpdf} parameter."
308 )
309 {
310   return bigpdfs ? SCM_BOOL_T : SCM_BOOL_F;
311 }
312
313 LY_DEFINE (ly_wide_char_2_utf_8, "ly:wide-char->utf-8",
314            1, 0, 0, (SCM wc),
315            "Encode the Unicode codepoint @var{wc}, an integer, as UTF-8.")
316 {
317   char buf[5];
318
319   LY_ASSERT_TYPE (scm_is_integer, wc, 1);
320   unsigned wide_char = (unsigned) scm_to_int (wc);
321   char *p = buf;
322
323   if (wide_char < 0x0080)
324     *p++ = (char)wide_char;
325   else if (wide_char < 0x0800)
326     {
327       *p++ = (char) (((wide_char >> 6)) | 0xC0);
328       *p++ = (char) (((wide_char) & 0x3F) | 0x80);
329     }
330   else if (wide_char < 0x10000)
331     {
332       *p++ = (char) (((wide_char >> 12)) | 0xE0);
333       *p++ = (char) (((wide_char >> 6) & 0x3F) | 0x80);
334       *p++ = (char) (((wide_char) & 0x3F) | 0x80);
335     }
336   else
337     {
338       *p++ = (char) (((wide_char >> 18)) | 0xF0);
339       *p++ = (char) (((wide_char >> 12) & 0x3F) | 0x80);
340       *p++ = (char) (((wide_char >> 6) & 0x3F) | 0x80);
341       *p++ = (char) (((wide_char) & 0x3F) | 0x80);
342     }
343   *p = 0;
344
345   return scm_from_utf8_string (buf);
346 }
347
348 LY_DEFINE (ly_effective_prefix, "ly:effective-prefix",
349            0, 0, 0, (),
350            "Return effective prefix.")
351 {
352   return ly_string2scm (lilypond_datadir);
353 }
354
355 LY_DEFINE (ly_chain_assoc_get, "ly:chain-assoc-get",
356            2, 2, 0, (SCM key, SCM achain, SCM default_value, SCM strict_checking),
357            "Return value for @var{key} from a list of alists @var{achain}."
358            "  If no entry is found, return @var{default-value} or @code{#f} if"
359            " @var{default-value} is not specified.  With @var{strict-checking}"
360            " set to @code{#t}, a programming_error is output in such cases.")
361 {
362   if (scm_is_pair (achain))
363     {
364       SCM handle = scm_assoc (key, scm_car (achain));
365       if (scm_is_pair (handle))
366         return scm_cdr (handle);
367       else
368         return ly_chain_assoc_get (key, scm_cdr (achain), default_value);
369     }
370
371   if (to_boolean (strict_checking))
372     {
373       string key_string = ly_scm2string
374                           (scm_object_to_string (key, SCM_UNDEFINED));
375       string default_value_string = ly_scm2string
376                                     (scm_object_to_string (default_value,
377                                                            SCM_UNDEFINED));
378       programming_error ("Cannot find key `"
379                          + key_string
380                          + "' in achain, setting to `"
381                          + default_value_string + "'.");
382     }
383
384   return SCM_UNBNDP (default_value) ? SCM_BOOL_F : default_value;
385 }
386
387 LY_DEFINE (ly_stderr_redirect, "ly:stderr-redirect",
388            1, 1, 0, (SCM file_name, SCM mode),
389            "Redirect stderr to @var{file-name}, opened with @var{mode}.")
390 {
391   LY_ASSERT_TYPE (scm_is_string, file_name, 1);
392
393   string m = "w";
394   string f = ly_scm2string (file_name);
395   FILE *stderrfile;
396   if (scm_is_string (mode))
397     m = ly_scm2string (mode);
398   /* dup2 and (fileno (current-error-port)) do not work with mingw'c
399      gcc -mwindows.  */
400   fflush (stderr);
401   stderrfile = freopen (f.c_str (), m.c_str (), stderr);
402   if (!stderrfile)
403     error (_f ("failed redirecting stderr to `%s'", f.c_str ()));
404   return SCM_UNSPECIFIED;
405 }
406
407 static SCM
408 accumulate_symbol (void * /* closure */,
409                    SCM key,
410                    SCM /* val */,
411                    SCM result)
412 {
413   return scm_cons (key, result);
414 }
415
416 LY_DEFINE (ly_hash_table_keys, "ly:hash-table-keys",
417            1, 0, 0, (SCM tab),
418            "Return a list of keys in @var{tab}.")
419 {
420   return scm_internal_hash_fold ((scm_t_hash_fold_fn) &accumulate_symbol,
421                                  NULL, SCM_EOL, tab);
422 }
423
424 LY_DEFINE (ly_camel_case_2_lisp_identifier, "ly:camel-case->lisp-identifier",
425            1, 0, 0, (SCM name_sym),
426            "Convert @code{FooBar_Bla} to @code{foo-bar-bla} style symbol.")
427 {
428   LY_ASSERT_TYPE (ly_is_symbol, name_sym, 1);
429
430   /*
431     TODO: should use strings instead?
432   */
433
434   const string in = ly_symbol2string (name_sym);
435   string result = camel_case_to_lisp_identifier (in);
436
437   return ly_symbol2scm (result.c_str ());
438 }
439
440 LY_DEFINE (ly_expand_environment, "ly:expand-environment",
441            1, 0, 0, (SCM str),
442            "Expand @code{$VAR} and @code{$@{VAR@}} in @var{str}.")
443 {
444   LY_ASSERT_TYPE (scm_is_string, str, 1);
445
446   return ly_string2scm (expand_environment_variables (ly_scm2string (str)));
447 }
448
449 LY_DEFINE (ly_truncate_list_x, "ly:truncate-list!",
450            2, 0, 0, (SCM lst, SCM i),
451            "Take at most the first @var{i} of list @var{lst}.")
452 {
453   LY_ASSERT_TYPE (scm_is_integer, i, 1);
454
455   int k = scm_to_int (i);
456   if (k == 0)
457     lst = SCM_EOL;
458   else
459     {
460       SCM s = lst;
461       k--;
462       for (; scm_is_pair (s) && k--; s = scm_cdr (s))
463         ;
464
465       if (scm_is_pair (s))
466         scm_set_cdr_x (s, SCM_EOL);
467     }
468   return lst;
469 }
470
471 string
472 format_single_argument (SCM arg, int precision, bool escape = false)
473 {
474   if (scm_is_integer (arg) && scm_is_true (scm_exact_p (arg)))
475     return (String_convert::int_string (scm_to_int (arg)));
476   else if (scm_is_number (arg))
477     {
478       Real val = scm_to_double (arg);
479
480       if (isnan (val) || isinf (val))
481         {
482           warning (_ ("Found infinity or nan in output.  Substituting 0.0"));
483           return ("0.0");
484           if (strict_infinity_checking)
485             abort ();
486         }
487       else
488         return (String_convert::form_string ("%.*lf", precision, val));
489     }
490   else if (scm_is_string (arg))
491     {
492       string s = ly_scm2string (arg);
493       if (escape)
494         {
495           // Escape backslashes and double quotes, wrap it in double quotes
496           replace_all (&s, "\\", "\\\\");
497           replace_all (&s, "\"", "\\\"");
498           // don't replace percents, since the png backend uses %d as escape sequence
499           // replace_all (&s, "%", "\\%");
500           replace_all (&s, "$", "\\$");
501           s = "\"" + s + "\"";
502         }
503       return s;
504     }
505   else if (scm_is_symbol (arg))
506     return (ly_symbol2string (arg));
507   else
508     {
509       ly_progress (scm_from_ascii_string ("\nUnsupported SCM value for format: ~a"),
510                    scm_list_1 (arg));
511     }
512
513   return "";
514 }
515
516 LY_DEFINE (ly_format, "ly:format",
517            1, 0, 1, (SCM str, SCM rest),
518            "LilyPond specific format, supporting @code{~a} and @code{~[0-9]f}."
519            "  Basic support for @code{~s} is also provided.")
520 {
521   LY_ASSERT_TYPE (scm_is_string, str, 1);
522
523   string format = ly_scm2string (str);
524   vector<string> results;
525
526   vsize i = 0;
527   while (i < format.size ())
528     {
529       vsize tilde = format.find ('~', i);
530
531       results.push_back (format.substr (i, (tilde - i)));
532
533       if (tilde == NPOS)
534         break;
535
536       tilde++;
537
538       char spec = format.at (tilde++);
539       if (spec == '~')
540         results.push_back ("~");
541       else
542         {
543           if (!scm_is_pair (rest))
544             {
545               programming_error (string (__FUNCTION__)
546                                  + ": not enough arguments for format.");
547               return ly_string2scm ("");
548             }
549
550           SCM arg = scm_car (rest);
551           rest = scm_cdr (rest);
552
553           int precision = 8;
554
555           if (spec == '$')
556             precision = 2;
557           else if (isdigit (spec))
558             {
559               precision = spec - '0';
560               spec = format.at (tilde++);
561             }
562
563           if (spec == 'a' || spec == 'A' || spec == 'f' || spec == '$')
564             results.push_back (format_single_argument (arg, precision));
565           else if (spec == 's' || spec == 'S')
566             results.push_back (format_single_argument (arg, precision, true));
567           else if (spec == 'l')
568             {
569               SCM s = arg;
570               for (; scm_is_pair (s); s = scm_cdr (s))
571                 {
572                   results.push_back (format_single_argument (scm_car (s), precision));
573                   if (!scm_is_null (scm_cdr (s)))
574                     results.push_back (" ");
575                 }
576
577               if (!scm_is_null (s))
578                 results.push_back (format_single_argument (s, precision));
579
580             }
581         }
582
583       i = tilde;
584     }
585
586   if (scm_is_pair (rest))
587     programming_error (string (__FUNCTION__)
588                        + ": too many arguments");
589
590   vsize len = 0;
591   for (vsize i = 0; i < results.size (); i++)
592     len += results[i].size ();
593
594   char *result = (char *) scm_malloc (len + 1);
595   char *ptr = result;
596   for (vsize i = 0; i < results.size (); i++)
597     {
598       // strcpy and strncpy cannot be used here
599       // because std::string may contain '\0' in its contents.
600       results[i].copy (ptr, results[i].size ());
601       ptr += results[i].size ();
602     }
603   *ptr = '\0';
604
605   return scm_take_locale_stringn (result, len);
606 }
607
608 int
609 ly_run_command (char *argv[], char **standard_output, char **standard_error)
610 {
611   GError *error = 0;
612   int exit_status = 0;
613   int flags = G_SPAWN_SEARCH_PATH;
614   if (!standard_output)
615     flags |= G_SPAWN_STDOUT_TO_DEV_NULL;
616   if (!standard_error)
617     flags |= G_SPAWN_STDERR_TO_DEV_NULL;
618   if (!g_spawn_sync (0, argv, 0, GSpawnFlags (flags),
619                      0, 0,
620                      standard_output, standard_error,
621                      &exit_status, &error))
622     {
623       warning (_f ("g_spawn_sync failed (%d): %s: %s",
624                    exit_status, argv[0], error->message));
625       g_error_free (error);
626       if (!exit_status)
627         exit_status = -1;
628     }
629
630   return exit_status;
631 }
632
633 static char *
634 ly_scm2utf8 (SCM str)
635 {
636   char *p = ly_scm2str0 (str);
637   char *g = g_locale_to_utf8 (p, -1, 0, 0, 0);
638   free (p);
639   return g;
640 }
641
642 LY_DEFINE (ly_spawn, "ly:spawn",
643            1, 0, 1, (SCM command, SCM rest),
644            "Simple interface to g_spawn_sync"
645            " @var{str}."
646            "  The error is formatted with @code{format} and @var{rest}.")
647
648 {
649   LY_ASSERT_TYPE (scm_is_string, command, 1);
650
651   int argc = scm_is_pair (rest) ? scm_ilength (rest) : 0;
652   char **argv = new char*[argc + 2];
653
654   int n = 0;
655   argv[n++] = ly_scm2utf8 (command);
656   for (SCM s = rest; scm_is_pair (s); s = scm_cdr (s))
657     argv[n++] = ly_scm2utf8 (scm_car (s));
658   argv[n] = 0;
659
660   char *standard_output = 0;
661   char *standard_error = 0;
662   // Always get the pointer to the stdout/stderr messages
663   int exit_status = ly_run_command (argv, &standard_output, &standard_error);
664
665   if (standard_output && standard_error)
666     {
667       // Print out stdout and stderr only in debug mode
668       debug_output (string ("\n") + standard_output + standard_error, true);
669     }
670
671   g_free (standard_error);
672   g_free (standard_output);
673
674   for (int i = 0; i < n; i++)
675     free (argv[i]);
676   delete[] argv;
677
678   return scm_from_int (exit_status);
679 }