]> git.donarmstrong.com Git - lilypond.git/blob - lily/lily-parser-scheme.cc
add unistd.h
[lilypond.git] / lily / lily-parser-scheme.cc
1 /*
2   lily-parser-scheme.cc -- implement Lily_parser bindings
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 2005 Han-Wen Nienhuys <hanwen@xs4all.nl>
7 */
8
9 #include <unistd.h>
10
11 #include "file-name.hh"
12 #include "file-path.hh"
13 #include "main.hh"
14 #include "lily-parser.hh"
15 #include "warn.hh"
16 #include "source.hh"
17 #include "lily-lexer.hh"
18 #include "score.hh"
19 #include "lilypond-key.hh"
20 #include "ly-module.hh"
21 #include "output-def.hh"
22 #include "book.hh"
23 #include "paper-book.hh"
24 #include "file-name-map.hh"
25
26 /* Do not append `!' suffix, since 1st argument is not modified. */
27 LY_DEFINE (ly_set_point_and_click, "ly:set-point-and-click",
28            1, 0, 0, (SCM what),
29            "Deprecated.")
30 {
31   (void) what;
32   warning (_f ("deprecated function called: %s", "ly:set-point-and-click"));
33   return SCM_UNSPECIFIED;
34 }
35
36 LY_DEFINE (ly_parse_file, "ly:parse-file",
37            1, 0, 0, (SCM name),
38            "Parse a single @code{.ly} file.  "
39            "Upon failure, throw @code{ly-file-failed} key.")
40 {
41   SCM_ASSERT_TYPE (scm_is_string (name), name, SCM_ARG1, __FUNCTION__, "string");
42   char const *file = scm_i_string_chars (name);
43   char const *extensions[] = {"ly", "", 0};
44
45   String file_name = global_path.find (file, extensions);
46
47   /* By default, use base name of input file for output file name,
48      write output to cwd; do not use root and directory parts of input
49      file name.  */
50   File_name out_file_name (file_name);
51
52   global_path.append (out_file_name.dir_);
53
54   out_file_name.ext_ = "";
55   out_file_name.root_ = "";
56   out_file_name.dir_ = "";
57
58   if (!output_name_global.is_empty ())
59     {
60       if (is_dir (output_name_global))
61         {
62           char cwd[PATH_MAX];
63           getcwd (cwd, PATH_MAX);
64
65           if (output_name_global != cwd)
66             {
67               global_path.prepend (cwd);
68               message (_f ("Changing working directory to `%s'",
69                            output_name_global.to_str0 ()));
70               chdir (output_name_global.to_str0 ());
71               
72             }
73           output_name_global = "";
74         }
75       else      
76         out_file_name = File_name (output_name_global);
77     }
78
79   String init;
80   if (!init_name_global.is_empty ())
81     init = init_name_global;
82   else
83     init = "init.ly";
84
85   String out_file = out_file_name.to_string ();
86
87   if (init.length () && global_path.find (init).is_empty ())
88     {
89       warning (_f ("can't find init file: `%s'", init));
90       warning (_f ("(search path: `%s')",
91                    global_path.to_string ().to_str0 ()));
92       exit (2);
93     }
94
95   if ((file_name != "-") && global_path.find (file_name).is_empty ())
96     {
97       warning (_f ("can't find file: `%s'", file_name));
98       scm_throw (ly_symbol2scm ("ly-file-failed"),
99                  scm_list_1 (scm_makfrom0str (file_name.to_str0 ())));
100     }
101   else
102     {
103       Sources sources;
104       sources.set_path (&global_path);
105
106       String mapped_fn = map_file_name (file_name);
107       message (_f ("Processing `%s'", mapped_fn.to_str0 ()));
108       progress_indication ("\n");
109
110       Lily_parser *parser = new Lily_parser (&sources);
111
112       parser->parse_file (init, file_name, out_file);
113
114       bool error = parser->error_level_;
115       scm_gc_unprotect_object (parser->self_scm ());
116       parser = 0;
117       if (error)
118         /* TODO: pass renamed input file too.  */
119         scm_throw (ly_symbol2scm ("ly-file-failed"),
120                    scm_list_1 (scm_makfrom0str (file_name.to_str0 ())));
121     }
122   return SCM_UNSPECIFIED;
123 }
124
125 LY_DEFINE (ly_parse_string, "ly:parse-string",
126            1, 0, 0, (SCM ly_code),
127            "Parse the string LY_CODE.  "
128            "Upon failure, throw @code{ly-file-failed} key.")
129 {
130   SCM_ASSERT_TYPE (scm_is_string (ly_code), ly_code, SCM_ARG1, __FUNCTION__, "string");
131
132   Sources sources;
133   sources.set_path (&global_path);
134   Lily_parser *parser = new Lily_parser (&sources);
135   scm_module_define (global_lily_module, ly_symbol2scm ("parser"),
136                      parser->self_scm ());
137   parser->parse_string (ly_scm2string (ly_code));
138   scm_gc_unprotect_object (parser->self_scm ());
139   parser = 0;
140
141   return SCM_UNSPECIFIED;
142 }
143
144 LY_DEFINE (ly_clone_parser, "ly:clone-parser",
145            1, 0, 0, (SCM parser_smob),
146            "Return a clone of PARSER_SMOB.")
147 {
148   Lily_parser *parser = unsmob_my_lily_parser (parser_smob);
149   Lily_parser *clone = new Lily_parser (*parser);
150
151   /* FIXME: should copy scopes too. */
152   return scm_gc_unprotect_object (clone->self_scm ());
153 }
154
155 LY_DEFINE (ly_parser_define, "ly:parser-define",
156            3, 0, 0, (SCM parser_smob, SCM symbol, SCM val),
157            "Bind SYMBOL to VAL in PARSER_SMOB's module.")
158 {
159   Lily_parser *parser = unsmob_my_lily_parser (parser_smob);
160   SCM_ASSERT_TYPE (scm_is_symbol (symbol), symbol, SCM_ARG2, __FUNCTION__, "symbol");
161   SCM_ASSERT_TYPE (parser, parser_smob, SCM_ARG2, __FUNCTION__, "parser");
162
163   parser->lexer_->set_identifier (scm_symbol_to_string (symbol), val);
164   return SCM_UNSPECIFIED;
165 }
166
167 LY_DEFINE (ly_parser_lookup, "ly:parser-lookup",
168            2, 0, 0, (SCM parser_smob, SCM symbol),
169            "Lookup @var{symbol} in @var{parser_smob}'s module.  "
170            "Undefined is '().")
171 {
172   Lily_parser *parser = unsmob_my_lily_parser (parser_smob);
173
174   SCM_ASSERT_TYPE (scm_is_symbol (symbol), symbol, SCM_ARG2, __FUNCTION__, "symbol");
175   SCM_ASSERT_TYPE (parser, parser_smob, SCM_ARG2, __FUNCTION__, "parser");
176
177   SCM val = parser->lexer_->lookup_identifier (ly_scm2string (scm_symbol_to_string (symbol)));
178   if (val != SCM_UNDEFINED)
179     return val;
180   else
181     return SCM_EOL;
182 }
183
184 LY_DEFINE (ly_parser_parse_string, "ly:parser-parse-string",
185            2, 0, 0, (SCM parser_smob, SCM ly_code),
186            "Parse the string LY_CODE with PARSER_SMOB."
187            "Upon failure, throw @code{ly-file-failed} key.")
188 {
189   Lily_parser *parser = unsmob_my_lily_parser (parser_smob);
190
191   SCM_ASSERT_TYPE (parser, parser_smob, SCM_ARG1, __FUNCTION__, "parser");
192   SCM_ASSERT_TYPE (scm_is_string (ly_code), ly_code, SCM_ARG2, __FUNCTION__, "string");
193
194   parser->parse_string (ly_scm2string (ly_code));
195
196   return SCM_UNSPECIFIED;
197 }
198
199 /* TODO: move this to Scheme?  Why take the parser arg, and all the back
200    & forth between scm and c++? */
201 LY_DEFINE (ly_parser_print_score, "ly:parser-print-score",
202            2, 0, 0,
203            (SCM parser_smob, SCM score_smob),
204            "Print score, i.e., the classic way.")
205 {
206   Lily_parser *parser = unsmob_my_lily_parser (parser_smob);
207   Score *score = unsmob_score (score_smob);
208
209   Object_key *key = new Lilypond_general_key (0, score->user_key_, 0);
210
211   if (score->error_found_)
212     return SCM_UNSPECIFIED;
213
214   SCM_ASSERT_TYPE (parser, parser_smob, SCM_ARG1, __FUNCTION__, "parser");
215   SCM_ASSERT_TYPE (score, score_smob, SCM_ARG2, __FUNCTION__, "score");
216
217   SCM header = ly_c_module_p (score->header_)
218     ? score->header_
219     : parser->lexer_->lookup_identifier ("$globalheader");
220
221   File_name outname (parser->output_basename_);
222   int *c = &parser->book_count_;
223   if (*c)
224     outname.base_ += "-" + to_string (*c);
225   (*c)++;
226
227   SCM os = scm_makfrom0str (outname.to_string ().to_str0 ());
228   SCM paper = get_paper (parser)->self_scm ();
229   for (int i = 0; i < score->defs_.size (); i++)
230     default_rendering (score->get_music (), score->defs_[i]->self_scm (),
231                        paper, header, os, key->self_scm ());
232
233   if (score->defs_.is_empty ())
234     {
235       Output_def *layout = get_layout (parser);
236       default_rendering (score->get_music (),
237                          layout->self_scm (),
238                          paper,
239                          header, os, key->self_scm ());
240       
241       scm_gc_unprotect_object (layout->self_scm ());
242     }
243
244   scm_gc_unprotect_object (paper);
245   scm_gc_unprotect_object (key->self_scm ());
246   return SCM_UNSPECIFIED;
247 }
248
249 LY_DEFINE (ly_parser_set_note_names, "ly:parser-set-note-names",
250            2, 0, 0, (SCM parser, SCM names),
251            "Replace current note names in @var{parser}. "
252            "@var{names} is an alist of symbols.  "
253            "This only has effect if the current mode is notes.")
254 {
255   Lily_parser *p = unsmob_my_lily_parser (parser);
256   SCM_ASSERT_TYPE (p, parser, SCM_ARG1, __FUNCTION__, "Lilypond parser");
257
258   if (p->lexer_->is_note_state ())
259     {
260       p->lexer_->pop_state ();
261       p->lexer_->push_note_state (alist_to_hashq (names));
262     }
263
264   return SCM_UNSPECIFIED;
265 }
266
267 LY_DEFINE (ly_parser_print_book, "ly:parser-print-book",
268            2, 0, 0, (SCM parser_smob, SCM book_smob),
269            "Print book.")
270 {
271   Lily_parser *parser = unsmob_my_lily_parser (parser_smob);
272   Book *book = unsmob_book (book_smob);
273   Output_def *bp = unsmob_output_def (parser->lexer_->lookup_identifier ("$defaultpaper"));
274
275   SCM_ASSERT_TYPE (parser, parser_smob, SCM_ARG1, __FUNCTION__, "Lilypond parser");
276   SCM_ASSERT_TYPE (book, book_smob, SCM_ARG2, __FUNCTION__, "Book");
277
278   /*  ugh. changing argument.*/
279   book->paper_ = bp;
280
281   File_name outname (parser->output_basename_);
282   int *c = &parser->book_count_;
283   if (*c)
284     outname.base_ += "-" + to_string (*c);
285   (*c)++;
286
287   Output_def *layout = get_layout (parser);
288   Paper_book *pb = book->process (outname.to_string (), layout);
289
290   if (pb)
291     {
292       pb->output (outname.to_string ());
293       scm_gc_unprotect_object (pb->self_scm ());
294     }
295
296   scm_gc_unprotect_object (layout->self_scm ());
297   return SCM_UNSPECIFIED;
298 }
299