]> git.donarmstrong.com Git - lilypond.git/blob - flower/source-file.cc
* config.hh.in: Add HAVE_SSTREAM.
[lilypond.git] / flower / 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--2000 Jan Nieuwenhuizen <janneke@gnu.org>
7   & Han-Wen Nienhuys <hanwen@cs.uu.nl>
8 */
9
10
11 #include <assert.h>
12 #if HAVE_SSTREAM
13 #include <sstream>
14 #else
15 #include <strstream.h>
16 #define istringstream(x) istrstream(x, length_i ()) 
17 #endif
18
19 #include "string.hh"
20 #include "flower-proto.hh"
21 #include "warn.hh"
22 #include "source-file.hh"
23 #include "simple-file-storage.hh"
24 #include "string-storage.hh"
25
26 Source_file::Source_file (String filename_str)
27 {
28   name_str_ = filename_str;
29   istream_p_ = 0;
30   storage_p_ = new Simple_file_storage (filename_str);
31   pos_ch_C_ = ch_C ();
32 }
33
34 Source_file::Source_file (String name_str, String data_str)
35 {
36   name_str_ = name_str;
37   istream_p_ = 0;
38   storage_p_ = new String_storage (data_str);
39   pos_ch_C_ = ch_C ();
40 }
41
42 std::istream*
43 Source_file::istream_l ()
44 {
45   /*
46     if (!name_str_.length_i ())
47       return &cin;
48     */
49
50   if (!istream_p_)
51     {
52       if (length_i ()) // can-t this be done without such a hack?
53         istream_p_ = new std::istringstream (ch_C ());
54       else
55         {
56           istream_p_ = new std::istringstream ("");
57           istream_p_->setstate (std::ios::eofbit);
58           //      istream_p_->set (ios::eofbit);
59         }
60     }
61   return istream_p_;
62 }
63
64 String
65 Source_file::file_line_column_str (char const *context_ch_C) const
66 {
67   if (!ch_C ())
68     return " (" + _ ("position unknown") + ")";
69   else
70     return name_str () + ":" + to_str (line_i (context_ch_C))
71       + ":" + to_str (char_i (context_ch_C));
72 }
73
74 String
75 Source_file::name_str () const
76 {
77   return name_str_;
78 }
79
80 Source_file::~Source_file ()
81 {
82   delete istream_p_;
83   istream_p_ = 0;
84   delete storage_p_;
85 }
86
87 Slice
88 Source_file::line_slice (char const* pos_ch_C) const
89 {
90   if (!in_b (pos_ch_C))
91     return Slice (0,0);
92
93   char const* data_ch_C = ch_C ();
94   char const * eof_C_ = data_ch_C + length_i ();
95
96   if (pos_ch_C == eof_C_)
97     pos_ch_C --;
98   char const* begin_ch_C = pos_ch_C;
99   while (begin_ch_C > data_ch_C)
100     if (*--begin_ch_C == '\n')
101       {
102         begin_ch_C++;
103         break;
104       }
105
106   char const* end_ch_C = pos_ch_C;
107   while (end_ch_C < eof_C_)
108     if (*end_ch_C++ == '\n')
109       {
110         end_ch_C--;
111         break;
112       }
113
114   return Slice (begin_ch_C - data_ch_C, end_ch_C - data_ch_C);
115 }
116
117 String
118 Source_file::line_str (char const* pos_ch_C) const
119 {
120   if (!in_b (pos_ch_C))
121     return "";
122
123   Slice line = line_slice (pos_ch_C);
124   char const* data_ch_C = ch_C ();
125   return String ((Byte const*)data_ch_C + line[LEFT], line.length ());
126 }
127
128 int
129 Source_file::char_i (char const* pos_ch_C) const
130 {
131   if (!in_b (pos_ch_C))
132     return 0;
133
134   char const* data_ch_C = ch_C ();
135   return pos_ch_C - (line_slice (pos_ch_C)[SMALLER] + data_ch_C);
136 }
137
138 int
139 Source_file::column_i (char const* pos_ch_C) const
140 {
141   if (!in_b (pos_ch_C))
142     return 0;
143
144   int ch_i = char_i (pos_ch_C);
145   String line = line_str (pos_ch_C);
146
147   int col_i = 0;
148   for (int i = 0; i < ch_i; i++)
149     if (line[i] == '\t')
150       col_i = (col_i / 8 + 1) * 8;
151     else
152       col_i++;
153
154   return col_i;
155 }
156
157 String
158 Source_file::error_str (char const* pos_ch_C) const
159 {
160   if (!in_b (pos_ch_C))
161     return " (" + _ ("position unknown") + ")";
162
163   int ch_i = char_i (pos_ch_C);
164   String line = line_str (pos_ch_C);
165   String context = line.left_str (ch_i)
166     + to_str ('\n')
167     + to_str (' ', column_i (pos_ch_C))
168     + line.cut_str (ch_i, INT_MAX);
169
170   return context;
171 }
172
173 bool
174 Source_file::in_b (char const* pos_ch_C) const
175 {
176   return (pos_ch_C && (pos_ch_C >= ch_C ()) && (pos_ch_C <= ch_C () + length_i ()));
177 }
178
179 int
180 Source_file::line_i (char const* pos_ch_C) const
181 {
182   if (!in_b (pos_ch_C))
183     return 0;
184
185   int i = 1;
186   char const* scan_ch_C = ch_C ();
187   if (!scan_ch_C)
188     return 0;
189
190   while (scan_ch_C < pos_ch_C)
191     if (*scan_ch_C++ == '\n')
192       i++;
193   return i;
194 }
195
196 int
197 Source_file::length_i () const
198 {
199   return storage_p_->length_i ();
200 }
201
202 char const *
203 Source_file::ch_C () const
204 {
205   return storage_p_->ch_C ();
206 }
207
208 void
209 Source_file::set_pos (char const * pos_ch_C)
210 {
211   if (in_b (pos_ch_C))
212     pos_ch_C_ = pos_ch_C;
213   else
214     error (error_str (pos_ch_C) + "invalid pos");
215 }
216
217 char const*
218 Source_file::seek_ch_C (int n)
219 {
220   char const* new_ch_C = ch_C () + n;
221   if (n < 0)
222     new_ch_C += length_i ();
223   if (in_b (new_ch_C))
224     pos_ch_C_ = new_ch_C;
225   else
226     error (error_str (new_ch_C) + "seek past eof");
227
228   return pos_ch_C_;
229 }
230
231 char const*
232 Source_file::forward_ch_C (int n)
233 {
234   char const* old_pos_C = pos_ch_C_;
235   char const* new_ch_C = pos_ch_C_ + n;
236   if (in_b (new_ch_C))
237     pos_ch_C_ = new_ch_C;
238   else
239     error (error_str (new_ch_C)  + "forward past eof");
240
241   return old_pos_C;
242 }
243
244 String
245 Source_file::get_str (int n)
246 {
247   String str ((Byte const*)forward_ch_C (n), n);
248   return str;
249 }