2 This file is part of LilyPond, the GNU music typesetter.
4 Copyright (C) 1998--2011 Jan Nieuwenhuizen <janneke@gnu.org>
5 Han-Wen Nienhuys <hanwen@xs4all.nl>
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.
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.
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/>.
25 #include <cstring> /* memset */
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"
37 #include "program-option.hh"
38 #include "relocate.hh"
39 #include "string-convert.hh"
43 LY_DEFINE (ly_start_environment
, "ly:start-environment",
45 "Return the environment (a list of strings) that was in"
46 " effect at program start.")
51 for (vsize i
= 0; i
< start_environment_global
.size (); i
++)
53 *tail
= scm_cons (ly_string2scm (start_environment_global
[i
]),
55 tail
= SCM_CDRLOC(*tail
);
62 LY_DEFINE (ly_find_file
, "ly:find-file",
64 "Return the absolute file name of @var{name},"
65 " or @code{#f} if not found.")
67 LY_ASSERT_TYPE (scm_is_string
, name
, 1);
69 string nm
= ly_scm2string (name
);
70 string file_name
= global_path
.find (nm
);
71 if (file_name
.empty ())
74 return ly_string2scm (file_name
);
78 Ugh. Gulped file is copied twice. (maybe thrice if you count stdio
81 LY_DEFINE (ly_gulp_file
, "ly:gulp-file",
82 1, 1, 0, (SCM name
, SCM size
),
83 "Read @var{size} characters from the file @var{name},"
84 " and return its contents in a string."
85 " If @var{size} is undefined, the entire file is read."
86 " The file is looked up using the search path.")
88 LY_ASSERT_TYPE (scm_is_string
, name
, 1);
90 if (size
!= SCM_UNDEFINED
)
92 LY_ASSERT_TYPE (scm_is_number
, size
, 2);
93 sz
= scm_to_int (size
);
96 string contents
= gulp_file_to_string (ly_scm2string (name
), true, sz
);
97 return scm_from_locale_stringn (contents
.c_str (), contents
.length ());
100 LY_DEFINE (ly_error
, "ly:error",
101 1, 0, 1, (SCM str
, SCM rest
),
102 "A Scheme callable function to issue the error @var{str}."
103 " The error is formatted with @code{format} and @var{rest}.")
105 LY_ASSERT_TYPE (scm_is_string
, str
, 1);
106 str
= scm_simple_format (SCM_BOOL_F
, str
, rest
);
107 error (ly_scm2string (str
));
108 return SCM_UNSPECIFIED
;
111 LY_DEFINE (ly_message
, "ly:message",
112 1, 0, 1, (SCM str
, SCM rest
),
113 "A Scheme callable function to issue the message @var{str}."
114 " The message is formatted with @code{format} and @var{rest}.")
116 LY_ASSERT_TYPE (scm_is_string
, str
, 1);
117 str
= scm_simple_format (SCM_BOOL_F
, str
, rest
);
118 message (ly_scm2string (str
));
119 return SCM_UNSPECIFIED
;
122 LY_DEFINE (ly_progress
, "ly:progress",
123 1, 0, 1, (SCM str
, SCM rest
),
124 "A Scheme callable function to print progress @var{str}."
125 " The message is formatted with @code{format} and @var{rest}.")
127 LY_ASSERT_TYPE (scm_is_string
, str
, 1);
128 str
= scm_simple_format (SCM_BOOL_F
, str
, rest
);
129 progress_indication (ly_scm2string (str
));
130 return SCM_UNSPECIFIED
;
133 LY_DEFINE (ly_programming_error
, "ly:programming-error",
134 1, 0, 1, (SCM str
, SCM rest
),
135 "A Scheme callable function to issue the internal warning"
136 " @var{str}. The message is formatted with @code{format}"
139 LY_ASSERT_TYPE (scm_is_string
, str
, 1);
140 str
= scm_simple_format (SCM_BOOL_F
, str
, rest
);
142 if (get_program_option ("warning-as-error"))
143 error (ly_scm2string (str
));
145 programming_error (ly_scm2string (str
));
147 return SCM_UNSPECIFIED
;
150 LY_DEFINE (ly_success
, "ly:success",
151 1, 0, 1, (SCM str
, SCM rest
),
152 "A Scheme callable function to issue a success message @var{str}."
153 " The message is formatted with @code{format} and @var{rest}.")
155 LY_ASSERT_TYPE (scm_is_string
, str
, 1);
156 str
= scm_simple_format (SCM_BOOL_F
, str
, rest
);
157 successful (ly_scm2string (str
));
158 return SCM_UNSPECIFIED
;
161 LY_DEFINE (ly_warning
, "ly:warning",
162 1, 0, 1, (SCM str
, SCM rest
),
163 "A Scheme callable function to issue the warning @var{str}."
164 " The message is formatted with @code{format} and @var{rest}.")
166 LY_ASSERT_TYPE (scm_is_string
, str
, 1);
167 str
= scm_simple_format (SCM_BOOL_F
, str
, rest
);
169 if (get_program_option ("warning-as-error"))
170 error (ly_scm2string (str
));
172 warning (ly_scm2string (str
));
174 return SCM_UNSPECIFIED
;
177 LY_DEFINE (ly_dir_p
, "ly:dir?",
179 "Is @var{s} a direction? Valid directions are @code{-1},"
180 " @code{0}, or@tie{}@code{1}, where @code{-1} represents"
181 " left or down, @code{1}@tie{}represents right or up, and @code{0}"
182 " represents a neutral direction.")
184 if (scm_is_number (s
))
186 int i
= scm_to_int (s
);
187 return (i
>= -1 && i
<= 1) ? SCM_BOOL_T
: SCM_BOOL_F
;
192 LY_DEFINE (ly_assoc_get
, "ly:assoc-get",
194 (SCM key
, SCM alist
, SCM default_value
, SCM strict_checking
),
195 "Return value if @var{key} in @var{alist}, else @var{default-value}"
196 " (or @code{#f} if not specified). If @var{strict-checking} is set"
197 " to @code{#t} and @var{key} is not in @var{alist}, a programming_error"
200 LY_ASSERT_TYPE(ly_cheap_is_list
, alist
, 2);
202 SCM handle
= scm_assoc (key
, alist
);
203 if (scm_is_pair (handle
))
204 return scm_cdr (handle
);
206 if (default_value
== SCM_UNDEFINED
)
207 default_value
= SCM_BOOL_F
;
209 if (strict_checking
== SCM_BOOL_T
)
211 string key_string
= ly_scm2string
212 (scm_object_to_string (key
, SCM_UNDEFINED
));
213 string default_value_string
= ly_scm2string
214 (scm_object_to_string (default_value
,
216 programming_error ("Cannot find key `" +
218 "' in alist, setting to `" +
219 default_value_string
+ "'.");
222 return default_value
;
225 LY_DEFINE (ly_string_substitute
, "ly:string-substitute",
226 3, 0, 0, (SCM a
, SCM b
, SCM s
),
227 "Replace string@tie{}@var{a} by string@tie{}@var{b} in"
228 " string@tie{}@var{s}.")
230 LY_ASSERT_TYPE (scm_is_string
, s
, 1);
231 LY_ASSERT_TYPE (scm_is_string
, b
, 2);
232 LY_ASSERT_TYPE (scm_is_string
, s
, 3);
234 string ss
= ly_scm2string (s
);
235 replace_all (&ss
, ly_scm2string (a
),
238 return ly_string2scm (ss
);
242 is_not_escape_character (Byte c
)
260 LY_DEFINE (ly_string_percent_encode
, "ly:string-percent-encode",
262 "Encode all characters in string @var{str} with hexadecimal"
263 " percent escape sequences, with the following exceptions:"
264 " characters @code{-}, @code{.}, @code{/}, and @code{_}; and"
265 " characters in ranges @code{0-9}, @code{A-Z}, and @code{a-z}.")
267 LY_ASSERT_TYPE (scm_is_string
, str
, 1);
269 string orig_str
= ly_scm2string (str
);
273 vsize n
= orig_str
.size ();
277 Byte cur
= orig_str
[i
];
279 if (is_not_escape_character (cur
))
284 new_str
+= String_convert::bin2hex (cur
);
290 return ly_string2scm (new_str
);
293 LY_DEFINE (ly_number_2_string
, "ly:number->string",
295 "Convert @var{s} to a string without generating many decimals.")
297 LY_ASSERT_TYPE (scm_is_number
, s
, 1);
299 char str
[400]; // ugh.
301 if (scm_exact_p (s
) == SCM_BOOL_F
)
303 Real
r (scm_to_double (s
));
304 if (isinf (r
) || isnan (r
))
306 programming_error (_ ("infinity or NaN encountered while converting Real number"));
307 programming_error (_ ("setting to zero"));
312 snprintf (str
, sizeof (str
), "%.4f", r
);
315 snprintf (str
, sizeof (str
), "%d", int (scm_to_int (s
)));
317 return scm_from_locale_string (str
);
320 LY_DEFINE (ly_version
, "ly:version", 0, 0, 0, (),
321 "Return the current lilypond version as a list, e.g.,"
322 " @code{(1 3 127 uu1)}.")
324 char const *vs
= "\'(" MAJOR_VERSION
" " MINOR_VERSION
" " PATCH_LEVEL
" " MY_PATCH_LEVEL
")";
326 return scm_c_eval_string ((char *)vs
);
329 LY_DEFINE (ly_unit
, "ly:unit", 0, 0, 0, (),
330 "Return the unit used for lengths as a string.")
332 return scm_from_locale_string (INTERNAL_UNIT
);
335 LY_DEFINE (ly_dimension_p
, "ly:dimension?", 1, 0, 0, (SCM d
),
336 "Return @var{d} as a number. Used to distinguish length"
337 " variables from normal numbers.")
339 return scm_number_p (d
);
345 LY_DEFINE (ly_protects
, "ly:protects",
347 "Return hash of protected objects.")
352 LY_DEFINE (ly_gettext
, "ly:gettext",
353 1, 0, 0, (SCM original
),
354 "A Scheme wrapper function for @code{gettext}.")
356 LY_ASSERT_TYPE (scm_is_string
, original
, 1);
357 return ly_string2scm (_ (ly_scm2string (original
).c_str ()));
360 LY_DEFINE (ly_output_formats
, "ly:output-formats",
362 "Formats passed to @option{--format} as a list of strings,"
363 " used for the output.")
365 vector
<string
> output_formats
= string_split (output_format_global
, ',');
368 int output_formats_count
= output_formats
.size ();
369 for (int i
= 0; i
< output_formats_count
; i
++)
370 lst
= scm_cons (ly_string2scm (output_formats
[i
]), lst
);
375 LY_DEFINE (ly_wide_char_2_utf_8
, "ly:wide-char->utf-8",
377 "Encode the Unicode codepoint @var{wc}, an integer, as UTF-8.")
381 LY_ASSERT_TYPE (scm_is_integer
, wc
, 1);
382 unsigned wide_char
= (unsigned) scm_to_int (wc
);
385 if (wide_char
< 0x0080)
386 *p
++ = (char)wide_char
;
387 else if (wide_char
< 0x0800)
389 *p
++ = (char) (((wide_char
>> 6)) | 0xC0);
390 *p
++ = (char) (((wide_char
) & 0x3F) | 0x80);
392 else if (wide_char
< 0x10000)
394 *p
++ = (char) (((wide_char
>> 12)) | 0xE0);
395 *p
++ = (char) (((wide_char
>> 6) & 0x3F) | 0x80);
396 *p
++ = (char) (((wide_char
) & 0x3F) | 0x80);
400 *p
++ = (char) (((wide_char
>> 18)) | 0xF0);
401 *p
++ = (char) (((wide_char
>> 12) & 0x3F) | 0x80);
402 *p
++ = (char) (((wide_char
>> 6) & 0x3F) | 0x80);
403 *p
++ = (char) (((wide_char
) & 0x3F) | 0x80);
407 return scm_from_locale_string (buf
);
410 LY_DEFINE (ly_effective_prefix
, "ly:effective-prefix",
412 "Return effective prefix.")
414 return ly_string2scm (lilypond_datadir
);
417 LY_DEFINE (ly_chain_assoc_get
, "ly:chain-assoc-get",
418 2, 2, 0, (SCM key
, SCM achain
, SCM default_value
, SCM strict_checking
),
419 "Return value for @var{key} from a list of alists @var{achain}."
420 " If no entry is found, return @var{default-value} or @code{#f} if"
421 " @var{default-value} is not specified. With @var{strict-checking}"
422 " set to @code{#t}, a programming_error is output in such cases.")
424 if (scm_is_pair (achain
))
426 SCM handle
= scm_assoc (key
, scm_car (achain
));
427 if (scm_is_pair (handle
))
428 return scm_cdr (handle
);
430 return ly_chain_assoc_get (key
, scm_cdr (achain
), default_value
);
433 if (strict_checking
== SCM_BOOL_T
)
435 string key_string
= ly_scm2string
436 (scm_object_to_string (key
, SCM_UNDEFINED
));
437 string default_value_string
= ly_scm2string
438 (scm_object_to_string (default_value
,
440 programming_error ("Cannot find key `" +
442 "' in achain, setting to `" +
443 default_value_string
+ "'.");
446 return default_value
== SCM_UNDEFINED
? SCM_BOOL_F
: default_value
;
450 LY_DEFINE (ly_stderr_redirect
, "ly:stderr-redirect",
451 1, 1, 0, (SCM file_name
, SCM mode
),
452 "Redirect stderr to @var{file-name}, opened with @var{mode}.")
454 LY_ASSERT_TYPE (scm_is_string
, file_name
, 1);
458 if (mode
!= SCM_UNDEFINED
&& scm_string_p (mode
))
459 m
= ly_scm2string (mode
);
460 /* dup2 and (fileno (current-error-port)) do not work with mingw'c
463 stderrfile
= freopen (ly_scm2string (file_name
).c_str (), m
.c_str (), stderr
);
464 return SCM_UNSPECIFIED
;
468 accumulate_symbol (void * /* closure */,
473 return scm_cons (key
, result
);
476 LY_DEFINE (ly_hash_table_keys
, "ly:hash-table-keys",
478 "Return a list of keys in @var{tab}.")
480 return scm_internal_hash_fold ((scm_t_hash_fold_fn
) &accumulate_symbol
,
484 LY_DEFINE (ly_camel_case_2_lisp_identifier
, "ly:camel-case->lisp-identifier",
485 1, 0, 0, (SCM name_sym
),
486 "Convert @code{FooBar_Bla} to @code{foo-bar-bla} style symbol.")
488 LY_ASSERT_TYPE (ly_is_symbol
, name_sym
, 1);
491 TODO: should use strings instead?
494 const string in
= ly_symbol2string (name_sym
);
495 string result
= camel_case_to_lisp_identifier (in
);
497 return ly_symbol2scm (result
.c_str ());
500 LY_DEFINE (ly_expand_environment
, "ly:expand-environment",
502 "Expand @code{$VAR} and @code{$@{VAR@}} in @var{str}.")
504 LY_ASSERT_TYPE (scm_is_string
, str
, 1);
506 return ly_string2scm (expand_environment_variables (ly_scm2string (str
)));
510 LY_DEFINE (ly_truncate_list_x
, "ly:truncate-list!",
511 2, 0, 0, (SCM lst
, SCM i
),
512 "Take at most the first @var{i} of list @var{lst}.")
514 LY_ASSERT_TYPE (scm_is_integer
, i
, 1);
516 int k
= scm_to_int (i
);
523 for (; scm_is_pair (s
) && k
--; s
= scm_cdr (s
))
527 scm_set_cdr_x (s
, SCM_EOL
);
533 format_single_argument (SCM arg
, int precision
, bool escape
= false)
535 if (scm_is_integer (arg
) && scm_exact_p (arg
) == SCM_BOOL_T
)
536 return (String_convert::int_string (scm_to_int (arg
)));
537 else if (scm_is_number (arg
))
539 Real val
= scm_to_double (arg
);
541 if (isnan (val
) || isinf (val
))
543 warning (_ ("Found infinity or nan in output. Substituting 0.0"));
545 if (strict_infinity_checking
)
549 return (String_convert::form_string ("%.*lf", precision
, val
));
551 else if (scm_is_string (arg
))
553 string s
= ly_scm2string (arg
);
556 // Escape backslashes and double quotes, wrap it in double quotes
557 replace_all (&s
, "\\", "\\\\");
558 replace_all (&s
, "\"", "\\\"");
559 // don't replace percents, since the png backend uses %d as escape sequence
560 // replace_all (&s, "%", "\\%");
561 replace_all (&s
, "$", "\\$");
566 else if (scm_is_symbol (arg
))
567 return (ly_symbol2string (arg
));
570 ly_progress (scm_from_locale_string ("\nUnsupported SCM value for format: ~a"),
578 LY_DEFINE (ly_format
, "ly:format",
579 1, 0, 1, (SCM str
, SCM rest
),
580 "LilyPond specific format, supporting @code{~a} and @code{~[0-9]f}."
581 " Basic support for @code{~s} is also provided.")
583 LY_ASSERT_TYPE (scm_is_string
, str
, 1);
585 string format
= ly_scm2string (str
);
586 vector
<string
> results
;
589 while (i
< format
.size ())
591 vsize tilde
= format
.find ('~', i
);
593 results
.push_back (format
.substr (i
, (tilde
-i
)));
600 char spec
= format
.at (tilde
++);
602 results
.push_back ("~");
605 if (!scm_is_pair (rest
))
607 programming_error (string (__FUNCTION__
)
608 + ": not enough arguments for format.");
609 return ly_string2scm ("");
612 SCM arg
= scm_car (rest
);
613 rest
= scm_cdr (rest
);
619 else if (isdigit (spec
))
621 precision
= spec
- '0';
622 spec
= format
.at (tilde
++);
625 if (spec
== 'a' || spec
== 'A' || spec
== 'f' || spec
== '$')
626 results
.push_back (format_single_argument (arg
, precision
));
627 else if (spec
== 's' || spec
== 'S')
628 results
.push_back (format_single_argument (arg
, precision
, true));
629 else if (spec
== 'l')
632 for (; scm_is_pair (s
); s
= scm_cdr (s
))
634 results
.push_back (format_single_argument (scm_car (s
), precision
));
635 if (scm_cdr (s
) != SCM_EOL
)
636 results
.push_back (" ");
640 results
.push_back (format_single_argument (s
, precision
));
648 if (scm_is_pair (rest
))
649 programming_error (string (__FUNCTION__
)
650 + ": too many arguments");
653 for (vsize i
= 0; i
< results
.size (); i
++)
654 len
+= results
[i
].size ();
656 char *result
= (char*) scm_malloc (len
+ 1);
658 for (vsize i
= 0; i
< results
.size (); i
++)
660 strncpy (ptr
, results
[i
].c_str (), results
[i
].size ());
661 ptr
+= results
[i
].size ();
665 return scm_take_locale_stringn (result
, len
);
669 ly_run_command (char *argv
[], char **standard_output
, char **standard_error
)
673 int flags
= G_SPAWN_SEARCH_PATH
;
674 if (!standard_output
)
675 flags
|= G_SPAWN_STDOUT_TO_DEV_NULL
;
677 flags
|= G_SPAWN_STDERR_TO_DEV_NULL
;
678 if (!g_spawn_sync (0, argv
, 0, GSpawnFlags (flags
),
680 standard_output
, standard_error
,
681 &exit_status
, &error
))
683 fprintf (stderr
, "failed (%d): %s: %s\n", exit_status
, argv
[0], error
->message
);
684 g_error_free (error
);
693 ly_scm2utf8 (SCM str
)
695 char *p
= ly_scm2str0 (str
);
696 char *g
= g_locale_to_utf8 (p
, -1, 0, 0, 0);
701 LY_DEFINE (ly_spawn
, "ly:spawn",
702 1, 0, 1, (SCM command
, SCM rest
),
703 "Simple interface to g_spawn_sync"
705 " The error is formatted with @code{format} and @var{rest}.")
708 LY_ASSERT_TYPE (scm_is_string
, command
, 1);
710 int argc
= scm_is_pair (rest
) ? scm_ilength (rest
) : 0;
711 char **argv
= new char*[argc
+ 2];
714 argv
[n
++] = ly_scm2utf8 (command
);
715 for (SCM s
= rest
; scm_is_pair (s
); s
= scm_cdr (s
))
716 argv
[n
++] = ly_scm2utf8 (scm_car (s
));
719 char *standard_output
= 0;
720 char *standard_error
= 0;
721 int exit_status
= be_verbose_global
722 ? ly_run_command (argv
, &standard_output
, &standard_error
)
723 : ly_run_command (argv
, 0, 0);
725 if (be_verbose_global
)
727 fprintf (stderr
, "\n%s", standard_output
);
728 fprintf (stderr
, "%s", standard_error
);
731 for (int i
= 0; i
< n
; i
++)
735 return scm_from_int (exit_status
);