]> git.lyx.org Git - lyx.git/blob - src/lyxlex.C
minimal effort implementation of:
[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 using lyx::support::compare_ascii_no_case;
27 using lyx::support::isStrDbl;
28 using lyx::support::isStrInt;
29 using lyx::support::ltrim;
30 using lyx::support::prefixIs;
31 using lyx::support::subst;
32 using lyx::support::trim;
33
34 using std::endl;
35 using std::string;
36 using std::istream;
37 using std::ostream;
38
39
40 LyXLex::LyXLex(keyword_item * tab, int num)
41         : pimpl_(new Pimpl(tab, num))
42 {}
43
44
45 LyXLex::~LyXLex()
46 {
47         delete pimpl_;
48 }
49
50
51 bool LyXLex::isOK() const
52 {
53         return pimpl_->is.good();
54 }
55
56
57 void LyXLex::setLineNo(int l)
58 {
59         pimpl_->lineno = l;
60 }
61
62
63 int LyXLex::getLineNo() const
64 {
65         return pimpl_->lineno;
66 }
67
68
69 istream & LyXLex::getStream()
70 {
71         return pimpl_->is;
72 }
73
74
75 void LyXLex::pushTable(keyword_item * tab, int num)
76 {
77         pimpl_->pushTable(tab, num);
78 }
79
80
81 void LyXLex::popTable()
82 {
83         pimpl_->popTable();
84 }
85
86
87 void LyXLex::printTable(ostream & os)
88 {
89         pimpl_->printTable(os);
90 }
91
92
93 void LyXLex::printError(string const & message) const
94 {
95         pimpl_->printError(message);
96 }
97
98
99 bool LyXLex::setFile(string const & filename)
100 {
101         return pimpl_->setFile(filename);
102 }
103
104
105 void LyXLex::setStream(istream & i)
106 {
107         pimpl_->setStream(i);
108 }
109
110
111 void LyXLex::setCommentChar(char c)
112 {
113         pimpl_->setCommentChar(c);
114 }
115
116 int LyXLex::lex()
117 {
118         return pimpl_->lex();
119 }
120
121
122 int LyXLex::getInteger() const
123 {
124         if (isStrInt(pimpl_->getString()))
125                 return convert<int>(pimpl_->getString());
126         pimpl_->printError("Bad integer `$$Token'");
127         return -1;
128 }
129
130
131 double LyXLex::getFloat() const
132 {
133         // replace comma with dot in case the file was written with
134         // the wrong locale (should be rare, but is easy enough to
135         // avoid).
136         string const str = subst(pimpl_->getString(), ",", ".");
137         if (isStrDbl(str))
138                 return convert<double>(str);
139         pimpl_->printError("Bad float `$$Token'");
140         return -1;
141 }
142
143
144 string const LyXLex::getString() const
145 {
146         return pimpl_->getString();
147 }
148
149
150 lyx::docstring const LyXLex::getDocString() const
151 {
152         return pimpl_->getDocString();
153 }
154
155
156 // I would prefer to give a tag number instead of an explicit token
157 // here, but it is not possible because Buffer::readDocument uses
158 // explicit tokens (JMarc)
159 string const LyXLex::getLongString(string const & endtoken)
160 {
161         string str, prefix;
162         bool firstline = true;
163
164         while (isOK()) {
165                 if (!eatLine())
166                         // blank line in the file being read
167                         continue;
168
169                 string const token = trim(getString(), " \t");
170
171                 lyxerr[Debug::PARSER] << "LongString: `"
172                                       << getString() << '\'' << endl;
173
174                 // We do a case independent comparison, like search_kw does.
175                 if (compare_ascii_no_case(token, endtoken) == 0)
176                         break;
177
178                 string tmpstr = getString();
179                 if (firstline) {
180                         string::size_type i(tmpstr.find_first_not_of(' '));
181                         if (i != string::npos)
182                                 prefix = tmpstr.substr(0, i);
183                         firstline = false;
184                         lyxerr[Debug::PARSER]
185                                 << "Prefix = `" << prefix << "\'" << endl;
186                 }
187
188                 // further lines in long strings may have the same
189                 // whitespace prefix as the first line. Remove it.
190                 if (prefix.length() && prefixIs(tmpstr, prefix)) {
191                         tmpstr.erase(0, prefix.length() - 1);
192                 }
193
194                 str += ltrim(tmpstr, "\t") + '\n';
195         }
196
197         if (!isOK()) {
198                 printError("Long string not ended by `" + endtoken + '\'');
199         }
200
201         return str;
202 }
203
204
205 bool LyXLex::getBool() const
206 {
207         if (pimpl_->getString() == "true") {
208                 return true;
209         } else if (pimpl_->getString() != "false") {
210                 pimpl_->printError("Bad boolean `$$Token'. "
211                                    "Use \"false\" or \"true\"");
212         }
213         return false;
214 }
215
216
217 bool LyXLex::eatLine()
218 {
219         return pimpl_->eatLine();
220 }
221
222
223 bool LyXLex::next(bool esc)
224 {
225         return pimpl_->next(esc);
226 }
227
228
229 bool LyXLex::nextToken()
230 {
231         return pimpl_->nextToken();
232 }
233
234
235 void LyXLex::pushToken(string const & pt)
236 {
237         pimpl_->pushToken(pt);
238 }
239
240 LyXLex::operator void const *() const
241 {
242         // This behaviour is NOT the same as the std::streams which would
243         // use fail() here. However, our implementation of getString() et al.
244         // can cause the eof() and fail() bits to be set, even though we
245         // haven't tried to read 'em.
246         return pimpl_->is.bad() ? 0 : this;
247 }
248
249
250 bool LyXLex::operator!() const
251 {
252         return pimpl_->is.bad();
253 }
254
255
256 LyXLex & LyXLex::operator>>(std::string & s)
257 {
258         if (isOK()) {
259                 next();
260                 s = getString();
261         }
262         return *this;
263 }
264
265
266 LyXLex & LyXLex::operator>>(double & s)
267 {
268         if (isOK()) {
269                 next();
270                 s = getFloat();
271         }
272         return *this;
273 }
274
275
276 LyXLex & LyXLex::operator>>(int & s)
277 {
278         if (isOK()) {
279                 next();
280                 s = getInteger();
281         }
282         return *this;
283 }
284
285
286 LyXLex & LyXLex::operator>>(unsigned int & s)
287 {
288         if (isOK()) {
289                 next();
290                 s = getInteger();
291         }
292         return *this;
293 }
294
295
296 LyXLex & LyXLex::operator>>(bool & s)
297 {
298         if (isOK()) {
299                 next();
300                 s = getBool();
301         }
302         return *this;
303 }
304
305
306 /// quotes a string, e.g. for use in preferences files or as an argument of the "log" dialog
307 string const LyXLex::quoteString(string const & arg)
308 {
309         std::ostringstream os;
310         os << '"' << subst(subst(arg, "\\", "\\\\"), "\"", "\\\"") << '"';
311         return os.str();
312 }