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