2 This file is part of LilyPond, the GNU music typesetter.
4 Copyright (C) 1998--2010 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 */
28 #include "dimensions.hh"
29 #include "file-name.hh"
30 #include "file-path.hh"
31 #include "international.hh"
32 #include "libc-extension.hh"
33 #include "lily-guile.hh"
36 #include "program-option.hh"
37 #include "relocate.hh"
38 #include "string-convert.hh"
42 LY_DEFINE (ly_start_environment
, "ly:start-environment",
44 "Return the environment (a list of strings) that was in"
45 " effect at program start.")
50 for (vsize i
= 0; i
< start_environment_global
.size (); i
++)
52 *tail
= scm_cons (ly_string2scm (start_environment_global
[i
]),
54 tail
= SCM_CDRLOC(*tail
);
61 LY_DEFINE (ly_find_file
, "ly:find-file",
63 "Return the absolute file name of @var{name},"
64 " or @code{#f} if not found.")
66 LY_ASSERT_TYPE (scm_is_string
, name
, 1);
68 string nm
= ly_scm2string (name
);
69 string file_name
= global_path
.find (nm
);
70 if (file_name
.empty ())
73 return ly_string2scm (file_name
);
77 Ugh. Gulped file is copied twice. (maybe thrice if you count stdio
80 LY_DEFINE (ly_gulp_file
, "ly:gulp-file",
81 1, 1, 0, (SCM name
, SCM size
),
82 "Read the file @var{name}, and return its contents in a string."
83 " The file is looked up using the search path.")
85 LY_ASSERT_TYPE (scm_is_string
, name
, 1);
87 if (size
!= SCM_UNDEFINED
)
89 LY_ASSERT_TYPE (scm_is_number
, size
, 2);
90 sz
= scm_to_int (size
);
93 string contents
= gulp_file_to_string (ly_scm2string (name
), true, sz
);
94 return scm_from_locale_stringn (contents
.c_str (), contents
.length ());
97 LY_DEFINE (ly_error
, "ly:error",
98 1, 0, 1, (SCM str
, SCM rest
),
99 "A Scheme callable function to issue the error @var{str}."
100 " The error is formatted with @code{format} and @var{rest}.")
102 LY_ASSERT_TYPE (scm_is_string
, str
, 1);
103 str
= scm_simple_format (SCM_BOOL_F
, str
, rest
);
104 error (ly_scm2string (str
));
105 return SCM_UNSPECIFIED
;
108 LY_DEFINE (ly_message
, "ly:message",
109 1, 0, 1, (SCM str
, SCM rest
),
110 "A Scheme callable function to issue the message @var{str}."
111 " The message is formatted with @code{format} and @var{rest}.")
113 LY_ASSERT_TYPE (scm_is_string
, str
, 1);
114 str
= scm_simple_format (SCM_BOOL_F
, str
, rest
);
115 message (ly_scm2string (str
));
116 return SCM_UNSPECIFIED
;
119 LY_DEFINE (ly_progress
, "ly:progress",
120 1, 0, 1, (SCM str
, SCM rest
),
121 "A Scheme callable function to print progress @var{str}."
122 " The message is formatted with @code{format} and @var{rest}.")
124 LY_ASSERT_TYPE (scm_is_string
, str
, 1);
125 str
= scm_simple_format (SCM_BOOL_F
, str
, rest
);
126 progress_indication (ly_scm2string (str
));
127 return SCM_UNSPECIFIED
;
130 LY_DEFINE (ly_programming_error
, "ly:programming-error",
131 1, 0, 1, (SCM str
, SCM rest
),
132 "A Scheme callable function to issue the internal warning"
133 " @var{str}. The message is formatted with @code{format}"
136 LY_ASSERT_TYPE (scm_is_string
, str
, 1);
137 str
= scm_simple_format (SCM_BOOL_F
, str
, rest
);
139 if (get_program_option ("warning-as-error"))
140 error (ly_scm2string (str
));
142 programming_error (ly_scm2string (str
));
144 return SCM_UNSPECIFIED
;
147 LY_DEFINE (ly_warning
, "ly:warning",
148 1, 0, 1, (SCM str
, SCM rest
),
149 "A Scheme callable function to issue the warning @code{str}."
150 " The message is formatted with @code{format} and @code{rest}.")
152 LY_ASSERT_TYPE (scm_is_string
, str
, 1);
153 str
= scm_simple_format (SCM_BOOL_F
, str
, rest
);
155 if (get_program_option ("warning-as-error"))
156 error (ly_scm2string (str
));
158 warning (ly_scm2string (str
));
160 return SCM_UNSPECIFIED
;
163 LY_DEFINE (ly_dir_p
, "ly:dir?",
165 "Is @var{s} a direction? Valid directions are @code{-1},"
166 " @code{0}, or@tie{}@code{1}, where @code{-1} represents"
167 " left or down, @code{1}@tie{}represents right or up, and @code{0}"
168 " represents a neutral direction.")
170 if (scm_is_number (s
))
172 int i
= scm_to_int (s
);
173 return (i
>= -1 && i
<= 1) ? SCM_BOOL_T
: SCM_BOOL_F
;
178 LY_DEFINE (ly_assoc_get
, "ly:assoc-get",
180 (SCM key
, SCM alist
, SCM default_value
, SCM strict_checking
),
181 "Return value if @var{key} in @var{alist}, else @var{default-value}"
182 " (or @code{#f} if not specified). If @var{strict-checking} is set"
183 " to @code{#t} and @var{key} is not in @var{alist}, a programming_error"
186 LY_ASSERT_TYPE(ly_cheap_is_list
, alist
, 2);
188 SCM handle
= scm_assoc (key
, alist
);
189 if (scm_is_pair (handle
))
190 return scm_cdr (handle
);
192 if (default_value
== SCM_UNDEFINED
)
193 default_value
= SCM_BOOL_F
;
195 if (strict_checking
== SCM_BOOL_T
)
197 string key_string
= ly_scm2string
198 (scm_object_to_string (key
, SCM_UNDEFINED
));
199 string default_value_string
= ly_scm2string
200 (scm_object_to_string (default_value
,
202 programming_error ("Cannot find key `" +
204 "' in alist, setting to `" +
205 default_value_string
+ "'.");
208 return default_value
;
211 LY_DEFINE (ly_string_substitute
, "ly:string-substitute",
212 3, 0, 0, (SCM a
, SCM b
, SCM s
),
213 "Replace string@tie{}@var{a} by string@tie{}@var{b} in"
214 " string@tie{}@var{s}.")
216 LY_ASSERT_TYPE (scm_is_string
, s
, 1);
217 LY_ASSERT_TYPE (scm_is_string
, b
, 2);
218 LY_ASSERT_TYPE (scm_is_string
, s
, 3);
220 string ss
= ly_scm2string (s
);
221 replace_all (&ss
, ly_scm2string (a
),
224 return ly_string2scm (ss
);
228 is_not_escape_character (Byte c
)
246 LY_DEFINE (ly_string_percent_encode
, "ly:string-percent-encode",
248 "Encode all characters in string @var{str} with hexadecimal"
249 " percent escape sequences, with the following exceptions:"
250 " characters @code{-}, @code{.}, @code{/}, and @code{_}; and"
251 " characters in ranges @code{0-9}, @code{A-Z}, and @code{a-z}.")
253 LY_ASSERT_TYPE (scm_is_string
, str
, 1);
255 string orig_str
= ly_scm2string (str
);
259 vsize n
= orig_str
.size ();
263 Byte cur
= orig_str
[i
];
265 if (is_not_escape_character (cur
))
270 new_str
+= String_convert::bin2hex (cur
);
276 return ly_string2scm (new_str
);
279 LY_DEFINE (ly_number_2_string
, "ly:number->string",
281 "Convert @var{num} to a string without generating many decimals.")
283 LY_ASSERT_TYPE (scm_is_number
, s
, 1);
285 char str
[400]; // ugh.
287 if (scm_exact_p (s
) == SCM_BOOL_F
)
289 Real
r (scm_to_double (s
));
290 if (isinf (r
) || isnan (r
))
292 programming_error (_ ("infinity or NaN encountered while converting Real number"));
293 programming_error (_ ("setting to zero"));
298 snprintf (str
, sizeof (str
), "%.4f", r
);
301 snprintf (str
, sizeof (str
), "%d", int (scm_to_int (s
)));
303 return scm_from_locale_string (str
);
306 LY_DEFINE (ly_version
, "ly:version", 0, 0, 0, (),
307 "Return the current lilypond version as a list, e.g.,"
308 " @code{(1 3 127 uu1)}.")
310 char const *vs
= "\'(" MAJOR_VERSION
" " MINOR_VERSION
" " PATCH_LEVEL
" " MY_PATCH_LEVEL
")";
312 return scm_c_eval_string ((char *)vs
);
315 LY_DEFINE (ly_unit
, "ly:unit", 0, 0, 0, (),
316 "Return the unit used for lengths as a string.")
318 return scm_from_locale_string (INTERNAL_UNIT
);
321 LY_DEFINE (ly_dimension_p
, "ly:dimension?", 1, 0, 0, (SCM d
),
322 "Return @var{d} as a number. Used to distinguish length"
323 " variables from normal numbers.")
325 return scm_number_p (d
);
331 LY_DEFINE (ly_protects
, "ly:protects",
333 "Return hash of protected objects.")
338 LY_DEFINE (ly_gettext
, "ly:gettext",
339 1, 0, 0, (SCM original
),
340 "A Scheme wrapper function for @code{gettext}.")
342 LY_ASSERT_TYPE (scm_is_string
, original
, 1);
343 return ly_string2scm (_ (ly_scm2string (original
).c_str ()));
346 LY_DEFINE (ly_output_formats
, "ly:output-formats",
348 "Formats passed to @option{--format} as a list of strings,"
349 " used for the output.")
351 vector
<string
> output_formats
= string_split (output_format_global
, ',');
354 int output_formats_count
= output_formats
.size ();
355 for (int i
= 0; i
< output_formats_count
; i
++)
356 lst
= scm_cons (ly_string2scm (output_formats
[i
]), lst
);
361 LY_DEFINE (ly_wide_char_2_utf_8
, "ly:wide-char->utf-8",
363 "Encode the Unicode codepoint @var{wc}, an integer, as UTF-8.")
367 LY_ASSERT_TYPE (scm_is_integer
, wc
, 1);
368 unsigned wide_char
= (unsigned) scm_to_int (wc
);
371 if (wide_char
< 0x0080)
372 *p
++ = (char)wide_char
;
373 else if (wide_char
< 0x0800)
375 *p
++ = (char) (((wide_char
>> 6)) | 0xC0);
376 *p
++ = (char) (((wide_char
) & 0x3F) | 0x80);
378 else if (wide_char
< 0x10000)
380 *p
++ = (char) (((wide_char
>> 12)) | 0xE0);
381 *p
++ = (char) (((wide_char
>> 6) & 0x3F) | 0x80);
382 *p
++ = (char) (((wide_char
) & 0x3F) | 0x80);
386 *p
++ = (char) (((wide_char
>> 18)) | 0xF0);
387 *p
++ = (char) (((wide_char
>> 12) & 0x3F) | 0x80);
388 *p
++ = (char) (((wide_char
>> 6) & 0x3F) | 0x80);
389 *p
++ = (char) (((wide_char
) & 0x3F) | 0x80);
393 return scm_from_locale_string (buf
);
396 LY_DEFINE (ly_effective_prefix
, "ly:effective-prefix",
398 "Return effective prefix.")
400 return ly_string2scm (lilypond_datadir
);
403 LY_DEFINE (ly_chain_assoc_get
, "ly:chain-assoc-get",
404 2, 2, 0, (SCM key
, SCM achain
, SCM default_value
, SCM strict_checking
),
405 "Return value for @var{key} from a list of alists @var{achain}."
406 " If no entry is found, return @var{default-value} or @code{#f} if"
407 " @var{default-value} is not specified. With @var{strict-checking}"
408 " set to @code{#t}, a programming_error is output in such cases.")
410 if (scm_is_pair (achain
))
412 SCM handle
= scm_assoc (key
, scm_car (achain
));
413 if (scm_is_pair (handle
))
414 return scm_cdr (handle
);
416 return ly_chain_assoc_get (key
, scm_cdr (achain
), default_value
);
419 if (strict_checking
== SCM_BOOL_T
)
421 string key_string
= ly_scm2string
422 (scm_object_to_string (key
, SCM_UNDEFINED
));
423 string default_value_string
= ly_scm2string
424 (scm_object_to_string (default_value
,
426 programming_error ("Cannot find key `" +
428 "' in achain, setting to `" +
429 default_value_string
+ "'.");
432 return default_value
== SCM_UNDEFINED
? SCM_BOOL_F
: default_value
;
436 LY_DEFINE (ly_stderr_redirect
, "ly:stderr-redirect",
437 1, 1, 0, (SCM file_name
, SCM mode
),
438 "Redirect stderr to @var{file-name}, opened with @var{mode}.")
440 LY_ASSERT_TYPE (scm_is_string
, file_name
, 1);
443 if (mode
!= SCM_UNDEFINED
&& scm_string_p (mode
))
444 m
= ly_scm2string (mode
);
445 /* dup2 and (fileno (current-error-port)) do not work with mingw'c
448 freopen (ly_scm2string (file_name
).c_str (), m
.c_str (), stderr
);
449 return SCM_UNSPECIFIED
;
453 accumulate_symbol (void * /* closure */,
458 return scm_cons (key
, result
);
461 LY_DEFINE (ly_hash_table_keys
, "ly:hash-table-keys",
463 "Return a list of keys in @var{tab}.")
465 return scm_internal_hash_fold ((Hash_closure_function
) & accumulate_symbol
,
469 LY_DEFINE (ly_camel_case_2_lisp_identifier
, "ly:camel-case->lisp-identifier",
470 1, 0, 0, (SCM name_sym
),
471 "Convert @code{FooBar_Bla} to @code{foo-bar-bla} style symbol.")
473 LY_ASSERT_TYPE (ly_is_symbol
, name_sym
, 1);
476 TODO: should use strings instead?
479 const string in
= ly_symbol2string (name_sym
);
480 string result
= camel_case_to_lisp_identifier (in
);
482 return ly_symbol2scm (result
.c_str ());
485 LY_DEFINE (ly_expand_environment
, "ly:expand-environment",
487 "Expand @code{$VAR} and @code{$@{VAR@}} in @var{str}.")
489 LY_ASSERT_TYPE (scm_is_string
, str
, 1);
491 return ly_string2scm (expand_environment_variables (ly_scm2string (str
)));
495 LY_DEFINE (ly_truncate_list_x
, "ly:truncate-list!",
496 2, 0, 0, (SCM lst
, SCM i
),
497 "Take at most the first @var{i} of list @var{lst}.")
499 LY_ASSERT_TYPE (scm_is_integer
, i
, 1);
501 int k
= scm_to_int (i
);
508 for (; scm_is_pair (s
) && k
--; s
= scm_cdr (s
))
512 scm_set_cdr_x (s
, SCM_EOL
);
518 format_single_argument (SCM arg
, int precision
, bool escape
= false)
520 if (scm_is_integer (arg
) && scm_exact_p (arg
) == SCM_BOOL_T
)
521 return (String_convert::int_string (scm_to_int (arg
)));
522 else if (scm_is_number (arg
))
524 Real val
= scm_to_double (arg
);
526 if (isnan (val
) || isinf (val
))
528 warning (_ ("Found infinity or nan in output. Substituting 0.0"));
530 if (strict_infinity_checking
)
534 return (String_convert::form_string ("%.*lf", precision
, val
));
536 else if (scm_is_string (arg
))
538 string s
= ly_scm2string (arg
);
541 // Escape backslashes and double quotes, wrap it in double quotes
542 replace_all (&s
, "\\", "\\\\");
543 replace_all (&s
, "\"", "\\\"");
544 // don't replace percents, since the png backend uses %d as escape sequence
545 // replace_all (&s, "%", "\\%");
546 replace_all (&s
, "$", "\\$");
551 else if (scm_is_symbol (arg
))
552 return (ly_symbol2string (arg
));
555 ly_progress (scm_from_locale_string ("Unsupported SCM value for format: ~a"),
563 LY_DEFINE (ly_format
, "ly:format",
564 1, 0, 1, (SCM str
, SCM rest
),
565 "LilyPond specific format, supporting @code{~a} and @code{~[0-9]f}. "
566 "Basic support for @code{~s} is also provided.")
568 LY_ASSERT_TYPE (scm_is_string
, str
, 1);
570 string format
= ly_scm2string (str
);
571 vector
<string
> results
;
574 while (i
< format
.size ())
576 vsize tilde
= format
.find ('~', i
);
578 results
.push_back (format
.substr (i
, (tilde
-i
)));
585 char spec
= format
.at (tilde
++);
587 results
.push_back ("~");
590 if (!scm_is_pair (rest
))
592 programming_error (string (__FUNCTION__
)
593 + ": not enough arguments for format.");
594 return ly_string2scm ("");
597 SCM arg
= scm_car (rest
);
598 rest
= scm_cdr (rest
);
604 else if (isdigit (spec
))
606 precision
= spec
- '0';
607 spec
= format
.at (tilde
++);
610 if (spec
== 'a' || spec
== 'A' || spec
== 'f' || spec
== '$')
611 results
.push_back (format_single_argument (arg
, precision
));
612 else if (spec
== 's' || spec
== 'S')
613 results
.push_back (format_single_argument (arg
, precision
, true));
614 else if (spec
== 'l')
617 for (; scm_is_pair (s
); s
= scm_cdr (s
))
619 results
.push_back (format_single_argument (scm_car (s
), precision
));
620 if (scm_cdr (s
) != SCM_EOL
)
621 results
.push_back (" ");
625 results
.push_back (format_single_argument (s
, precision
));
633 if (scm_is_pair (rest
))
634 programming_error (string (__FUNCTION__
)
635 + ": too many arguments");
638 for (vsize i
= 0; i
< results
.size (); i
++)
639 len
+= results
[i
].size ();
641 char *result
= (char*) scm_malloc (len
+ 1);
643 for (vsize i
= 0; i
< results
.size (); i
++)
645 strncpy (ptr
, results
[i
].c_str (), results
[i
].size ());
646 ptr
+= results
[i
].size ();
650 return scm_take_locale_stringn (result
, len
);