]> git.donarmstrong.com Git - lilypond.git/blob - lily/general-scheme.cc
Run grand-replace (issue 3765)
[lilypond.git] / lily / general-scheme.cc
1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3
4   Copyright (C) 1998--2014 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 (size != SCM_UNDEFINED)
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_locale_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 (default_value == SCM_UNDEFINED)
132     default_value = SCM_BOOL_F;
133
134   if (strict_checking == SCM_BOOL_T)
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_exact_p (s) == SCM_BOOL_F)
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_locale_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_locale_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   return scm_protects;
275 }
276
277 LY_DEFINE (ly_gettext, "ly:gettext",
278            1, 0, 0, (SCM original),
279            "A Scheme wrapper function for @code{gettext}.")
280 {
281   LY_ASSERT_TYPE (scm_is_string, original, 1);
282   return ly_string2scm (_ (ly_scm2string (original).c_str ()));
283 }
284
285 LY_DEFINE (ly_output_formats, "ly:output-formats",
286            0, 0, 0, (),
287            "Formats passed to @option{--format} as a list of strings,"
288            " used for the output.")
289 {
290   vector<string> output_formats = string_split (output_format_global, ',');
291
292   SCM lst = SCM_EOL;
293   int output_formats_count = output_formats.size ();
294   for (int i = 0; i < output_formats_count; i++)
295     lst = scm_cons (ly_string2scm (output_formats[i]), lst);
296
297   return lst;
298 }
299
300 LY_DEFINE (ly_wide_char_2_utf_8, "ly:wide-char->utf-8",
301            1, 0, 0, (SCM wc),
302            "Encode the Unicode codepoint @var{wc}, an integer, as UTF-8.")
303 {
304   char buf[5];
305
306   LY_ASSERT_TYPE (scm_is_integer, wc, 1);
307   unsigned wide_char = (unsigned) scm_to_int (wc);
308   char *p = buf;
309
310   if (wide_char < 0x0080)
311     *p++ = (char)wide_char;
312   else if (wide_char < 0x0800)
313     {
314       *p++ = (char) (((wide_char >> 6)) | 0xC0);
315       *p++ = (char) (((wide_char) & 0x3F) | 0x80);
316     }
317   else if (wide_char < 0x10000)
318     {
319       *p++ = (char) (((wide_char >> 12)) | 0xE0);
320       *p++ = (char) (((wide_char >> 6) & 0x3F) | 0x80);
321       *p++ = (char) (((wide_char) & 0x3F) | 0x80);
322     }
323   else
324     {
325       *p++ = (char) (((wide_char >> 18)) | 0xF0);
326       *p++ = (char) (((wide_char >> 12) & 0x3F) | 0x80);
327       *p++ = (char) (((wide_char >> 6) & 0x3F) | 0x80);
328       *p++ = (char) (((wide_char) & 0x3F) | 0x80);
329     }
330   *p = 0;
331
332   return scm_from_locale_string (buf);
333 }
334
335 LY_DEFINE (ly_effective_prefix, "ly:effective-prefix",
336            0, 0, 0, (),
337            "Return effective prefix.")
338 {
339   return ly_string2scm (lilypond_datadir);
340 }
341
342 LY_DEFINE (ly_chain_assoc_get, "ly:chain-assoc-get",
343            2, 2, 0, (SCM key, SCM achain, SCM default_value, SCM strict_checking),
344            "Return value for @var{key} from a list of alists @var{achain}."
345            "  If no entry is found, return @var{default-value} or @code{#f} if"
346            " @var{default-value} is not specified.  With @var{strict-checking}"
347            " set to @code{#t}, a programming_error is output in such cases.")
348 {
349   if (scm_is_pair (achain))
350     {
351       SCM handle = scm_assoc (key, scm_car (achain));
352       if (scm_is_pair (handle))
353         return scm_cdr (handle);
354       else
355         return ly_chain_assoc_get (key, scm_cdr (achain), default_value);
356     }
357
358   if (strict_checking == SCM_BOOL_T)
359     {
360       string key_string = ly_scm2string
361                           (scm_object_to_string (key, SCM_UNDEFINED));
362       string default_value_string = ly_scm2string
363                                     (scm_object_to_string (default_value,
364                                                            SCM_UNDEFINED));
365       programming_error ("Cannot find key `"
366                          + key_string
367                          + "' in achain, setting to `"
368                          + default_value_string + "'.");
369     }
370
371   return default_value == SCM_UNDEFINED ? SCM_BOOL_F : default_value;
372 }
373
374 LY_DEFINE (ly_stderr_redirect, "ly:stderr-redirect",
375            1, 1, 0, (SCM file_name, SCM mode),
376            "Redirect stderr to @var{file-name}, opened with @var{mode}.")
377 {
378   LY_ASSERT_TYPE (scm_is_string, file_name, 1);
379
380   string m = "w";
381   string f = ly_scm2string (file_name);
382   FILE *stderrfile;
383   if (scm_is_string (mode))
384     m = ly_scm2string (mode);
385   /* dup2 and (fileno (current-error-port)) do not work with mingw'c
386      gcc -mwindows.  */
387   fflush (stderr);
388   stderrfile = freopen (f.c_str (), m.c_str (), stderr);
389   if (!stderrfile)
390     error (_f ("failed redirecting stderr to `%s'", f.c_str ()));
391   return SCM_UNSPECIFIED;
392 }
393
394 static SCM
395 accumulate_symbol (void * /* closure */,
396                    SCM key,
397                    SCM /* val */,
398                    SCM result)
399 {
400   return scm_cons (key, result);
401 }
402
403 LY_DEFINE (ly_hash_table_keys, "ly:hash-table-keys",
404            1, 0, 0, (SCM tab),
405            "Return a list of keys in @var{tab}.")
406 {
407   return scm_internal_hash_fold ((scm_t_hash_fold_fn) &accumulate_symbol,
408                                  NULL, SCM_EOL, tab);
409 }
410
411 LY_DEFINE (ly_camel_case_2_lisp_identifier, "ly:camel-case->lisp-identifier",
412            1, 0, 0, (SCM name_sym),
413            "Convert @code{FooBar_Bla} to @code{foo-bar-bla} style symbol.")
414 {
415   LY_ASSERT_TYPE (ly_is_symbol, name_sym, 1);
416
417   /*
418     TODO: should use strings instead?
419   */
420
421   const string in = ly_symbol2string (name_sym);
422   string result = camel_case_to_lisp_identifier (in);
423
424   return ly_symbol2scm (result.c_str ());
425 }
426
427 LY_DEFINE (ly_expand_environment, "ly:expand-environment",
428            1, 0, 0, (SCM str),
429            "Expand @code{$VAR} and @code{$@{VAR@}} in @var{str}.")
430 {
431   LY_ASSERT_TYPE (scm_is_string, str, 1);
432
433   return ly_string2scm (expand_environment_variables (ly_scm2string (str)));
434 }
435
436 LY_DEFINE (ly_truncate_list_x, "ly:truncate-list!",
437            2, 0, 0, (SCM lst, SCM i),
438            "Take at most the first @var{i} of list @var{lst}.")
439 {
440   LY_ASSERT_TYPE (scm_is_integer, i, 1);
441
442   int k = scm_to_int (i);
443   if (k == 0)
444     lst = SCM_EOL;
445   else
446     {
447       SCM s = lst;
448       k--;
449       for (; scm_is_pair (s) && k--; s = scm_cdr (s))
450         ;
451
452       if (scm_is_pair (s))
453         scm_set_cdr_x (s, SCM_EOL);
454     }
455   return lst;
456 }
457
458 string
459 format_single_argument (SCM arg, int precision, bool escape = false)
460 {
461   if (scm_is_integer (arg) && scm_exact_p (arg) == SCM_BOOL_T)
462     return (String_convert::int_string (scm_to_int (arg)));
463   else if (scm_is_number (arg))
464     {
465       Real val = scm_to_double (arg);
466
467       if (isnan (val) || isinf (val))
468         {
469           warning (_ ("Found infinity or nan in output.  Substituting 0.0"));
470           return ("0.0");
471           if (strict_infinity_checking)
472             abort ();
473         }
474       else
475         return (String_convert::form_string ("%.*lf", precision, val));
476     }
477   else if (scm_is_string (arg))
478     {
479       string s = ly_scm2string (arg);
480       if (escape)
481         {
482           // Escape backslashes and double quotes, wrap it in double quotes
483           replace_all (&s, "\\", "\\\\");
484           replace_all (&s, "\"", "\\\"");
485           // don't replace percents, since the png backend uses %d as escape sequence
486           // replace_all (&s, "%", "\\%");
487           replace_all (&s, "$", "\\$");
488           s = "\"" + s + "\"";
489         }
490       return s;
491     }
492   else if (scm_is_symbol (arg))
493     return (ly_symbol2string (arg));
494   else
495     {
496       ly_progress (scm_from_locale_string ("\nUnsupported SCM value for format: ~a"),
497                    scm_list_1 (arg));
498     }
499
500   return "";
501 }
502
503 LY_DEFINE (ly_format, "ly:format",
504            1, 0, 1, (SCM str, SCM rest),
505            "LilyPond specific format, supporting @code{~a} and @code{~[0-9]f}."
506            "  Basic support for @code{~s} is also provided.")
507 {
508   LY_ASSERT_TYPE (scm_is_string, str, 1);
509
510   string format = ly_scm2string (str);
511   vector<string> results;
512
513   vsize i = 0;
514   while (i < format.size ())
515     {
516       vsize tilde = format.find ('~', i);
517
518       results.push_back (format.substr (i, (tilde - i)));
519
520       if (tilde == NPOS)
521         break;
522
523       tilde++;
524
525       char spec = format.at (tilde++);
526       if (spec == '~')
527         results.push_back ("~");
528       else
529         {
530           if (!scm_is_pair (rest))
531             {
532               programming_error (string (__FUNCTION__)
533                                  + ": not enough arguments for format.");
534               return ly_string2scm ("");
535             }
536
537           SCM arg = scm_car (rest);
538           rest = scm_cdr (rest);
539
540           int precision = 8;
541
542           if (spec == '$')
543             precision = 2;
544           else if (isdigit (spec))
545             {
546               precision = spec - '0';
547               spec = format.at (tilde++);
548             }
549
550           if (spec == 'a' || spec == 'A' || spec == 'f' || spec == '$')
551             results.push_back (format_single_argument (arg, precision));
552           else if (spec == 's' || spec == 'S')
553             results.push_back (format_single_argument (arg, precision, true));
554           else if (spec == 'l')
555             {
556               SCM s = arg;
557               for (; scm_is_pair (s); s = scm_cdr (s))
558                 {
559                   results.push_back (format_single_argument (scm_car (s), precision));
560                   if (scm_cdr (s) != SCM_EOL)
561                     results.push_back (" ");
562                 }
563
564               if (s != SCM_EOL)
565                 results.push_back (format_single_argument (s, precision));
566
567             }
568         }
569
570       i = tilde;
571     }
572
573   if (scm_is_pair (rest))
574     programming_error (string (__FUNCTION__)
575                        + ": too many arguments");
576
577   vsize len = 0;
578   for (vsize i = 0; i < results.size (); i++)
579     len += results[i].size ();
580
581   char *result = (char *) scm_malloc (len + 1);
582   char *ptr = result;
583   for (vsize i = 0; i < results.size (); i++)
584     {
585       strncpy (ptr, results[i].c_str (), results[i].size ());
586       ptr += results[i].size ();
587     }
588   *ptr = '\0';
589
590   return scm_take_locale_stringn (result, len);
591 }
592
593 int
594 ly_run_command (char *argv[], char **standard_output, char **standard_error)
595 {
596   GError *error = 0;
597   int exit_status = 0;
598   int flags = G_SPAWN_SEARCH_PATH;
599   if (!standard_output)
600     flags |= G_SPAWN_STDOUT_TO_DEV_NULL;
601   if (!standard_error)
602     flags |= G_SPAWN_STDERR_TO_DEV_NULL;
603   if (!g_spawn_sync (0, argv, 0, GSpawnFlags (flags),
604                      0, 0,
605                      standard_output, standard_error,
606                      &exit_status, &error))
607     {
608       fprintf (stderr, "failed (%d): %s: %s\n", exit_status, argv[0], error->message);
609       g_error_free (error);
610       if (!exit_status)
611         exit_status = -1;
612     }
613
614   return exit_status;
615 }
616
617 static char *
618 ly_scm2utf8 (SCM str)
619 {
620   char *p = ly_scm2str0 (str);
621   char *g = g_locale_to_utf8 (p, -1, 0, 0, 0);
622   free (p);
623   return g;
624 }
625
626 LY_DEFINE (ly_spawn, "ly:spawn",
627            1, 0, 1, (SCM command, SCM rest),
628            "Simple interface to g_spawn_sync"
629            " @var{str}."
630            "  The error is formatted with @code{format} and @var{rest}.")
631
632 {
633   LY_ASSERT_TYPE (scm_is_string, command, 1);
634
635   int argc = scm_is_pair (rest) ? scm_ilength (rest) : 0;
636   char **argv = new char*[argc + 2];
637
638   int n = 0;
639   argv[n++] = ly_scm2utf8 (command);
640   for (SCM s = rest; scm_is_pair (s); s = scm_cdr (s))
641     argv[n++] = ly_scm2utf8 (scm_car (s));
642   argv[n] = 0;
643
644   char *standard_output = 0;
645   char *standard_error = 0;
646   // Always get the pointer to the stdout/stderr messages
647   int exit_status = ly_run_command (argv, &standard_output, &standard_error);
648
649   // Print out stdout and stderr only in debug mode
650   debug_output (string ("\n") + standard_output + standard_error, true);
651
652   for (int i = 0; i < n; i++)
653     free (argv[i]);
654   delete[] argv;
655
656   return scm_from_int (exit_status);
657 }