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