]> git.lyx.org Git - lyx.git/blob - src/lyxlex.C
update build instructions (Qt 4.2.2 etc.)
[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_->is.good();
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         if (isStrInt(pimpl_->getString()))
128                 return convert<int>(pimpl_->getString());
129         pimpl_->printError("Bad integer `$$Token'");
130         return -1;
131 }
132
133
134 double LyXLex::getFloat() const
135 {
136         // replace comma with dot in case the file was written with
137         // the wrong locale (should be rare, but is easy enough to
138         // avoid).
139         string const str = subst(pimpl_->getString(), ",", ".");
140         if (isStrDbl(str))
141                 return convert<double>(str);
142         pimpl_->printError("Bad float `$$Token'");
143         return -1;
144 }
145
146
147 string const LyXLex::getString() const
148 {
149         return pimpl_->getString();
150 }
151
152
153 docstring const LyXLex::getDocString() const
154 {
155         return pimpl_->getDocString();
156 }
157
158
159 // I would prefer to give a tag number instead of an explicit token
160 // here, but it is not possible because Buffer::readDocument uses
161 // explicit tokens (JMarc)
162 string const LyXLex::getLongString(string const & endtoken)
163 {
164         string str, prefix;
165         bool firstline = true;
166
167         while (isOK()) {
168                 if (!eatLine())
169                         // blank line in the file being read
170                         continue;
171
172                 string const token = trim(getString(), " \t");
173
174                 lyxerr[Debug::PARSER] << "LongString: `"
175                                       << getString() << '\'' << endl;
176
177                 // We do a case independent comparison, like search_kw does.
178                 if (compare_ascii_no_case(token, endtoken) == 0)
179                         break;
180
181                 string tmpstr = getString();
182                 if (firstline) {
183                         string::size_type i(tmpstr.find_first_not_of(' '));
184                         if (i != string::npos)
185                                 prefix = tmpstr.substr(0, i);
186                         firstline = false;
187                         lyxerr[Debug::PARSER]
188                                 << "Prefix = `" << prefix << "\'" << endl;
189                 }
190
191                 // further lines in long strings may have the same
192                 // whitespace prefix as the first line. Remove it.
193                 if (prefix.length() && prefixIs(tmpstr, prefix)) {
194                         tmpstr.erase(0, prefix.length() - 1);
195                 }
196
197                 str += ltrim(tmpstr, "\t") + '\n';
198         }
199
200         if (!isOK()) {
201                 printError("Long string not ended by `" + endtoken + '\'');
202         }
203
204         return str;
205 }
206
207
208 bool LyXLex::getBool() const
209 {
210         if (pimpl_->getString() == "true") {
211                 return true;
212         } else if (pimpl_->getString() != "false") {
213                 pimpl_->printError("Bad boolean `$$Token'. "
214                                    "Use \"false\" or \"true\"");
215         }
216         return false;
217 }
218
219
220 bool LyXLex::eatLine()
221 {
222         return pimpl_->eatLine();
223 }
224
225
226 bool LyXLex::next(bool esc)
227 {
228         return pimpl_->next(esc);
229 }
230
231
232 bool LyXLex::nextToken()
233 {
234         return pimpl_->nextToken();
235 }
236
237
238 void LyXLex::pushToken(string const & pt)
239 {
240         pimpl_->pushToken(pt);
241 }
242
243 LyXLex::operator void const *() const
244 {
245         // This behaviour is NOT the same as the std::streams which would
246         // use fail() here. However, our implementation of getString() et al.
247         // can cause the eof() and fail() bits to be set, even though we
248         // haven't tried to read 'em.
249         return pimpl_->is.bad() ? 0 : this;
250 }
251
252
253 bool LyXLex::operator!() const
254 {
255         return pimpl_->is.bad();
256 }
257
258
259 LyXLex & LyXLex::operator>>(std::string & s)
260 {
261         if (isOK()) {
262                 next();
263                 s = getString();
264         }
265         return *this;
266 }
267
268
269 LyXLex & LyXLex::operator>>(docstring & s)
270 {
271         if (isOK()) {
272                 next();
273                 s = getDocString();
274         }
275         return *this;
276 }
277
278
279 LyXLex & LyXLex::operator>>(double & s)
280 {
281         if (isOK()) {
282                 next();
283                 s = getFloat();
284         }
285         return *this;
286 }
287
288
289 LyXLex & LyXLex::operator>>(int & s)
290 {
291         if (isOK()) {
292                 next();
293                 s = getInteger();
294         }
295         return *this;
296 }
297
298
299 LyXLex & LyXLex::operator>>(unsigned int & s)
300 {
301         if (isOK()) {
302                 next();
303                 s = getInteger();
304         }
305         return *this;
306 }
307
308
309 LyXLex & LyXLex::operator>>(bool & s)
310 {
311         if (isOK()) {
312                 next();
313                 s = getBool();
314         }
315         return *this;
316 }
317
318
319 /// quotes a string, e.g. for use in preferences files or as an argument of the "log" dialog
320 string const LyXLex::quoteString(string const & arg)
321 {
322         std::ostringstream os;
323         os << '"' << subst(subst(arg, "\\", "\\\\"), "\"", "\\\"") << '"';
324         return os.str();
325 }
326
327
328 } // namespace lyx