]> git.lyx.org Git - lyx.git/blob - src/lyxlex.C
remove redundant lyxerr.debugging checks; macro LYXERR already checks whether the...
[lyx.git] / src / lyxlex.C
1 /**
2  * \file lyxlex.C
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Alejandro Aguilar Sierra
7  * \author Lars Gullik Bjønnes
8  * \author Jean-Marc Lasgouttes
9  * \author John Levon
10  *
11  * Full author contact details are available in file CREDITS.
12  */
13
14 #include <config.h>
15
16 #include "lyxlex.h"
17
18 #include "debug.h"
19 #include "lyxlex_pimpl.h"
20
21 #include "support/convert.h"
22 #include "support/lstrings.h"
23
24 #include <sstream>
25
26
27 namespace lyx {
28
29 using support::compare_ascii_no_case;
30 using support::isStrDbl;
31 using support::isStrInt;
32 using support::ltrim;
33 using support::prefixIs;
34 using support::subst;
35 using support::trim;
36
37 using std::endl;
38 using std::string;
39 using std::istream;
40 using std::ostream;
41
42
43 LyXLex::LyXLex(keyword_item * tab, int num)
44         : pimpl_(new Pimpl(tab, num))
45 {}
46
47
48 LyXLex::~LyXLex()
49 {
50         delete pimpl_;
51 }
52
53
54 bool LyXLex::isOK() const
55 {
56         return pimpl_->inputAvailable();
57 }
58
59
60 void LyXLex::setLineNo(int l)
61 {
62         pimpl_->lineno = l;
63 }
64
65
66 int LyXLex::getLineNo() const
67 {
68         return pimpl_->lineno;
69 }
70
71
72 istream & LyXLex::getStream()
73 {
74         return pimpl_->is;
75 }
76
77
78 void LyXLex::pushTable(keyword_item * tab, int num)
79 {
80         pimpl_->pushTable(tab, num);
81 }
82
83
84 void LyXLex::popTable()
85 {
86         pimpl_->popTable();
87 }
88
89
90 void LyXLex::printTable(ostream & os)
91 {
92         pimpl_->printTable(os);
93 }
94
95
96 void LyXLex::printError(string const & message) const
97 {
98         pimpl_->printError(message);
99 }
100
101
102 bool LyXLex::setFile(support::FileName const & filename)
103 {
104         return pimpl_->setFile(filename);
105 }
106
107
108 void LyXLex::setStream(istream & i)
109 {
110         pimpl_->setStream(i);
111 }
112
113
114 void LyXLex::setCommentChar(char c)
115 {
116         pimpl_->setCommentChar(c);
117 }
118
119 int LyXLex::lex()
120 {
121         return pimpl_->lex();
122 }
123
124
125 int LyXLex::getInteger() const
126 {
127         lastReadOk_ = pimpl_->status == LEX_DATA || pimpl_->status == LEX_TOKEN;
128         if (!lastReadOk_) {
129                 pimpl_->printError("integer token missing");
130                 return -1;
131         }
132
133         if (isStrInt(pimpl_->getString()))
134                 return convert<int>(pimpl_->getString());
135
136         lastReadOk_ = false;
137         pimpl_->printError("Bad integer `$$Token'");
138         return -1;
139 }
140
141
142 double LyXLex::getFloat() const
143 {
144         // replace comma with dot in case the file was written with
145         // the wrong locale (should be rare, but is easy enough to
146         // avoid).
147         lastReadOk_ = pimpl_->status == LEX_DATA || pimpl_->status == LEX_TOKEN;
148         if (!lastReadOk_) {
149                 pimpl_->printError("float token missing");
150                 return -1;
151         }
152
153         string const str = subst(pimpl_->getString(), ",", ".");
154         if (isStrDbl(str))
155                 return convert<double>(str);
156
157         lastReadOk_ = false;
158         pimpl_->printError("Bad float `$$Token'");
159         return -1;
160 }
161
162
163 string const LyXLex::getString() const
164 {
165         lastReadOk_ = pimpl_->status == LEX_DATA || pimpl_->status == LEX_TOKEN;
166
167         if (lastReadOk_)
168         return pimpl_->getString();
169
170         return string();
171 }
172
173
174 docstring const LyXLex::getDocString() const
175 {
176         lastReadOk_ = pimpl_->status == LEX_DATA || pimpl_->status == LEX_TOKEN;
177         
178         if (lastReadOk_)
179                 return pimpl_->getDocString();
180
181         return docstring();
182 }
183
184
185 // I would prefer to give a tag number instead of an explicit token
186 // here, but it is not possible because Buffer::readDocument uses
187 // explicit tokens (JMarc)
188 string const LyXLex::getLongString(string const & endtoken)
189 {
190         string str, prefix;
191         bool firstline = true;
192
193         while (pimpl_->is) { //< eatLine only reads from is, not from pushTok
194                 if (!eatLine())
195                         // blank line in the file being read
196                         continue;
197
198                 string const token = trim(getString(), " \t");
199
200                 LYXERR(Debug::PARSER) << "LongString: `"
201                                       << getString() << '\'' << endl;
202
203                 // We do a case independent comparison, like search_kw does.
204                 if (compare_ascii_no_case(token, endtoken) == 0)
205                         break;
206
207                 string tmpstr = getString();
208                 if (firstline) {
209                         string::size_type i(tmpstr.find_first_not_of(' '));
210                         if (i != string::npos)
211                                 prefix = tmpstr.substr(0, i);
212                         firstline = false;
213                         LYXERR(Debug::PARSER)
214                                 << "Prefix = `" << prefix << "\'" << endl;
215                 }
216
217                 // further lines in long strings may have the same
218                 // whitespace prefix as the first line. Remove it.
219                 if (prefix.length() && prefixIs(tmpstr, prefix)) {
220                         tmpstr.erase(0, prefix.length() - 1);
221                 }
222
223                 str += ltrim(tmpstr, "\t") + '\n';
224         }
225
226         if (!pimpl_->is) {
227                 printError("Long string not ended by `" + endtoken + '\'');
228         }
229
230         return str;
231 }
232
233
234 bool LyXLex::getBool() const
235 {
236         if (pimpl_->getString() == "true") {
237                 lastReadOk_ = true;
238                 return true;
239         } else if (pimpl_->getString() != "false") {
240                 pimpl_->printError("Bad boolean `$$Token'. "
241                                    "Use \"false\" or \"true\"");
242                 lastReadOk_ = false;
243         }
244         lastReadOk_ = true;
245         return false;
246 }
247
248
249 bool LyXLex::eatLine()
250 {
251         return pimpl_->eatLine();
252 }
253
254
255 bool LyXLex::next(bool esc)
256 {
257         return pimpl_->next(esc);
258 }
259
260
261 bool LyXLex::nextToken()
262 {
263         return pimpl_->nextToken();
264 }
265
266
267 void LyXLex::pushToken(string const & pt)
268 {
269         pimpl_->pushToken(pt);
270 }
271
272 LyXLex::operator void const *() const
273 {
274         // This behaviour is NOT the same as the std::streams which would
275         // use fail() here. However, our implementation of getString() et al.
276         // can cause the eof() and fail() bits to be set, even though we
277         // haven't tried to read 'em.
278         return lastReadOk_? this: 0;
279 }
280
281
282 bool LyXLex::operator!() const
283 {
284         return !lastReadOk_;
285 }
286
287
288 LyXLex & LyXLex::operator>>(std::string & s)
289 {
290         if (isOK()) {
291                 next();
292                 s = getString();
293         } else {
294                 lastReadOk_ = false;
295         }
296         return *this;
297 }
298
299
300 LyXLex & LyXLex::operator>>(docstring & s)
301 {
302         if (isOK()) {
303                 next();
304                 s = getDocString();
305         } else {
306                 lastReadOk_ = false;
307         }
308         return *this;
309 }
310
311
312 LyXLex & LyXLex::operator>>(double & s)
313 {
314         if (isOK()) {
315                 next();
316                 s = getFloat();
317         } else {
318                 lastReadOk_ = false;
319         }
320         return *this;
321 }
322
323
324 LyXLex & LyXLex::operator>>(int & s)
325 {
326         if (isOK()) {
327                 next();
328                 s = getInteger();
329         } else {
330                 lastReadOk_ = false;
331         }
332         return *this;
333 }
334
335
336 LyXLex & LyXLex::operator>>(unsigned int & s)
337 {
338         if (isOK()) {
339                 next();
340                 s = getInteger();
341         } else {
342                 lastReadOk_ = false;
343         }
344         return *this;
345 }
346
347
348 LyXLex & LyXLex::operator>>(bool & s)
349 {
350         if (isOK()) {
351                 next();
352                 s = getBool();
353         } else {
354                 lastReadOk_ = false;
355         }
356         return *this;
357 }
358
359
360 /// quotes a string, e.g. for use in preferences files or as an argument of the "log" dialog
361 string const LyXLex::quoteString(string const & arg)
362 {
363         std::ostringstream os;
364         os << '"' << subst(subst(arg, "\\", "\\\\"), "\"", "\\\"") << '"';
365         return os.str();
366 }
367
368
369 } // namespace lyx