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