]> git.donarmstrong.com Git - lilypond.git/blob - lily/source-file.cc
* lily/kpath.cc (kpathsea_gulp_file_to_string):
[lilypond.git] / lily / source-file.cc
1 /*
2   source-file.cc -- implement Source_file
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 1997--2004 Jan Nieuwenhuizen <janneke@gnu.org>
7   Han-Wen Nienhuys <hanwen@cs.uu.nl>
8 */
9
10 #include "config.h"
11
12 #include <stdio.h>
13 #include <assert.h>
14 #if HAVE_SSTREAM
15 #include <sstream>
16 #else
17 #include <strstream>
18 #define istringstream(x) istrstream(x, length ()) 
19 #endif
20
21 #include "string.hh"
22 #include "flower-proto.hh"
23 #include "warn.hh"
24 #include "source-file.hh"
25 #include "array.hh"
26
27 void
28 Source_file::load_stdin ()
29 {
30   length_ = 0;
31
32   int c;
33   Array<char> chs;              // ugh.
34   while ((c = fgetc (stdin)) != EOF)
35     chs.push (c);
36
37   chs.push (0);
38   length_ = chs.size ();
39   contents_str0_ = chs.remove_array ();
40 }
41
42 char*
43 gulp_file (String filename, int *filesize)
44 {
45   /* "b" must ensure to open literally, avoiding text (CR/LF)
46      conversions.  */
47   FILE *f = fopen (filename.to_str0 (), "rb");
48   if (!f)
49     {
50       warning (_f ("can't open file: `%s'", filename.to_str0 ()));
51       return 0;
52     }
53
54   fseek (f, 0, SEEK_END);
55   *filesize = ftell (f);
56   rewind (f);
57
58   char *str = new char[*filesize + 1];
59   str[*filesize] = 0;
60
61   int bytes_read = fread (str, sizeof (char), *filesize, f);
62   if (bytes_read != *filesize)
63     warning (_f ("Huh?  Got %d, expected %d characters", bytes_read,
64                  *filesize));
65   fclose (f);
66
67   return str;
68 }
69
70 /*
71   Unused.
72  */
73 Source_file::Source_file (String filename, String data)
74 {
75   name_ = filename;
76   istream_ = 0;
77   contents_str0_ = data.get_copy_str0();
78   length_ = data.length ();
79   pos_str0_ = to_str0 ();
80   init_port ();
81 }
82
83 Source_file::Source_file (String filename_string)
84 {
85   name_ = filename_string;
86   istream_ = 0;
87   contents_str0_ = 0;
88
89   if (filename_string == "-")
90     load_stdin ();
91   else
92     contents_str0_ = gulp_file (filename_string, &length_);
93   
94   pos_str0_ = to_str0 ();
95
96   init_port ();
97
98   for (int i = 0; i < length_; i++)
99     if (contents_str0_[i] == '\n')
100       newline_locations_.push (contents_str0_ + i);
101 }
102
103 void
104 Source_file::init_port ()
105 {
106   SCM str =scm_makfrom0str (contents_str0_);
107   
108   str_port_ = scm_mkstrport (SCM_INUM0, str, SCM_OPN | SCM_RDNG,
109                              __FUNCTION__);
110   scm_set_port_filename_x (str_port_,
111                            scm_makfrom0str (name_.get_str0()));
112 }
113
114 int
115 Source_file::tell () const
116 {
117   return pos_str0_  - contents_str0_; 
118 }
119
120 std::istream*
121 Source_file::get_istream ()
122 {
123   if (!istream_)
124     {
125       if (length ()) // can-t this be done without such a hack?
126         istream_ = new std::istringstream (to_str0 ());
127       else
128         {
129           istream_ = new std::istringstream ("");
130           istream_->setstate (std::ios::eofbit);
131           //      istream_->set (ios::eofbit);
132         }
133     }
134   return istream_;
135 }
136
137 String
138 Source_file::file_line_column_string (char const *context_str0) const
139 {
140   if (!to_str0 ())
141     return " (" + _ ("position unknown") + ")";
142   else
143     return name_string () + ":" + to_string (get_line (context_str0))
144       + ":" + to_string (get_char (context_str0));
145 }
146
147 String
148 Source_file::name_string () const
149 {
150   return name_;
151 }
152
153 Source_file::~Source_file ()
154 {
155   delete istream_;
156   istream_ = 0;
157   delete[] contents_str0_;
158 }
159
160 Slice
161 Source_file::line_slice (char const* pos_str0) const
162 {
163   if (!contains (pos_str0))
164     return Slice (0,0);
165
166   char const* data_str0 = to_str0 ();
167   char const * eof_C_ = data_str0 + length ();
168
169   if (pos_str0 == eof_C_)
170     pos_str0 --;
171   char const* begin_str0 = pos_str0;
172   while (begin_str0 > data_str0)
173     if (*--begin_str0 == '\n')
174       {
175         begin_str0++;
176         break;
177       }
178
179   char const* end_str0 = pos_str0;
180   while (end_str0 < eof_C_)
181     if (*end_str0++ == '\n')
182       {
183         end_str0--;
184         break;
185       }
186
187   return Slice (begin_str0 - data_str0, end_str0 - data_str0);
188 }
189
190 String
191 Source_file::line_string (char const* pos_str0) const
192 {
193   if (!contains (pos_str0))
194     return "";
195
196   Slice line = line_slice (pos_str0);
197   char const* data_str0 = to_str0 ();
198   return String ((Byte const*)data_str0 + line[LEFT], line.length ());
199 }
200
201 int
202 Source_file::get_char (char const* pos_str0) const
203 {
204   if (!contains (pos_str0))
205     return 0;
206
207   char const* data_str0 = to_str0 ();
208   return pos_str0 - (line_slice (pos_str0)[SMALLER] + data_str0);
209 }
210
211 int
212 Source_file::get_column (char const* pos_str0) const
213 {
214   if (!contains (pos_str0))
215     return 0;
216
217   int ch_i = get_char (pos_str0);
218   String line = line_string (pos_str0);
219
220   int col_i = 0;
221   for (int i = 0; i < ch_i; i++)
222     if (line[i] == '\t')
223       col_i = (col_i / 8 + 1) * 8;
224     else
225       col_i++;
226
227   return col_i;
228 }
229
230 String
231 Source_file::error_string (char const* pos_str0) const
232 {
233   if (!contains (pos_str0))
234     return " (" + _ ("position unknown") + ")";
235
236   int ch_i = get_char (pos_str0);
237   String line = line_string (pos_str0);
238   String context = line.left_string (ch_i)
239     + to_string ('\n')
240     + to_string (' ', get_column (pos_str0))
241     + line.cut_string (ch_i, INT_MAX);
242
243   return context;
244 }
245
246 bool
247 Source_file::contains (char const* pos_str0) const
248 {
249   return (pos_str0 && (pos_str0 >= to_str0 ()) && (pos_str0 <= to_str0 () + length ()));
250 }
251
252 int
253 Source_file::get_line (char const* pos_str0) const
254 {
255   if (!contains (pos_str0))
256     return 0;
257
258   if (!newline_locations_.size ())
259     return 1;
260   
261   int lo=0;
262   int hi = newline_locations_.size ();
263
264   if (newline_locations_[lo] > pos_str0)
265     return 1;
266   
267   if (newline_locations_[hi-1] < pos_str0)
268     return hi;
269   
270   binary_search_bounds (newline_locations_,
271                         pos_str0, 
272                         Link_array<char>::default_compare,
273                         &lo, &hi);
274
275   if (*pos_str0 == '\n')
276     lo --;
277   return lo + 2;
278 }
279
280 int
281 Source_file::length () const
282 {
283   return length_;
284 }
285
286 char const *
287 Source_file::to_str0 () const
288 {
289   return contents_str0_;
290 }
291
292 void
293 Source_file::set_pos (char const * pos_str0)
294 {
295   if (contains (pos_str0))
296     pos_str0_ = pos_str0;
297   else
298     error (error_string (pos_str0) + "invalid pos");
299 }
300
301 char const*
302 Source_file::seek_str0 (int n)
303 {
304   char const* new_str0 = to_str0 () + n;
305   if (n < 0)
306     new_str0 += length ();
307   if (contains (new_str0))
308     pos_str0_ = new_str0;
309   else
310     error (error_string (new_str0) + "seek past eof");
311
312   return pos_str0_;
313 }
314
315 char const*
316 Source_file::forward_str0 (int n)
317 {
318   char const* old_pos = pos_str0_;
319   char const* new_str0 = pos_str0_ + n;
320   if (contains (new_str0))
321     pos_str0_ = new_str0;
322   else
323     error (error_string (new_str0)  + "forward past eof");
324
325   return old_pos;
326 }
327
328 String
329 Source_file::get_string (int n)
330 {
331   String str = String ((Byte const*)forward_str0 (n), n);
332   return str;
333 }