/** * \file lyxlex.C * This file is part of LyX, the document processor. * Licence details can be found in the file COPYING. * * \author Alejandro Aguilar Sierra * \author Lars Gullik Bjønnes * \author Jean-Marc Lasgouttes * \author John Levon * * Full author contact details are available in file CREDITS. */ #include #include "lyxlex.h" #include "debug.h" #include "lyxlex_pimpl.h" #include "support/convert.h" #include "support/lstrings.h" #include namespace lyx { using support::compare_ascii_no_case; using support::isStrDbl; using support::isStrInt; using support::ltrim; using support::prefixIs; using support::subst; using support::trim; using std::endl; using std::string; using std::istream; using std::ostream; LyXLex::LyXLex(keyword_item * tab, int num) : pimpl_(new Pimpl(tab, num)) {} LyXLex::~LyXLex() { delete pimpl_; } bool LyXLex::isOK() const { return pimpl_->is.good(); } void LyXLex::setLineNo(int l) { pimpl_->lineno = l; } int LyXLex::getLineNo() const { return pimpl_->lineno; } istream & LyXLex::getStream() { return pimpl_->is; } void LyXLex::pushTable(keyword_item * tab, int num) { pimpl_->pushTable(tab, num); } void LyXLex::popTable() { pimpl_->popTable(); } void LyXLex::printTable(ostream & os) { pimpl_->printTable(os); } void LyXLex::printError(string const & message) const { pimpl_->printError(message); } bool LyXLex::setFile(string const & filename) { return pimpl_->setFile(filename); } void LyXLex::setStream(istream & i) { pimpl_->setStream(i); } void LyXLex::setCommentChar(char c) { pimpl_->setCommentChar(c); } int LyXLex::lex() { return pimpl_->lex(); } int LyXLex::getInteger() const { if (isStrInt(pimpl_->getString())) return convert(pimpl_->getString()); pimpl_->printError("Bad integer `$$Token'"); return -1; } double LyXLex::getFloat() const { // replace comma with dot in case the file was written with // the wrong locale (should be rare, but is easy enough to // avoid). string const str = subst(pimpl_->getString(), ",", "."); if (isStrDbl(str)) return convert(str); pimpl_->printError("Bad float `$$Token'"); return -1; } string const LyXLex::getString() const { return pimpl_->getString(); } docstring const LyXLex::getDocString() const { return pimpl_->getDocString(); } // I would prefer to give a tag number instead of an explicit token // here, but it is not possible because Buffer::readDocument uses // explicit tokens (JMarc) string const LyXLex::getLongString(string const & endtoken) { string str, prefix; bool firstline = true; while (isOK()) { if (!eatLine()) // blank line in the file being read continue; string const token = trim(getString(), " \t"); lyxerr[Debug::PARSER] << "LongString: `" << getString() << '\'' << endl; // We do a case independent comparison, like search_kw does. if (compare_ascii_no_case(token, endtoken) == 0) break; string tmpstr = getString(); if (firstline) { string::size_type i(tmpstr.find_first_not_of(' ')); if (i != string::npos) prefix = tmpstr.substr(0, i); firstline = false; lyxerr[Debug::PARSER] << "Prefix = `" << prefix << "\'" << endl; } // further lines in long strings may have the same // whitespace prefix as the first line. Remove it. if (prefix.length() && prefixIs(tmpstr, prefix)) { tmpstr.erase(0, prefix.length() - 1); } str += ltrim(tmpstr, "\t") + '\n'; } if (!isOK()) { printError("Long string not ended by `" + endtoken + '\''); } return str; } bool LyXLex::getBool() const { if (pimpl_->getString() == "true") { return true; } else if (pimpl_->getString() != "false") { pimpl_->printError("Bad boolean `$$Token'. " "Use \"false\" or \"true\""); } return false; } bool LyXLex::eatLine() { return pimpl_->eatLine(); } bool LyXLex::next(bool esc) { return pimpl_->next(esc); } bool LyXLex::nextToken() { return pimpl_->nextToken(); } void LyXLex::pushToken(string const & pt) { pimpl_->pushToken(pt); } LyXLex::operator void const *() const { // This behaviour is NOT the same as the std::streams which would // use fail() here. However, our implementation of getString() et al. // can cause the eof() and fail() bits to be set, even though we // haven't tried to read 'em. return pimpl_->is.bad() ? 0 : this; } bool LyXLex::operator!() const { return pimpl_->is.bad(); } LyXLex & LyXLex::operator>>(std::string & s) { if (isOK()) { next(); s = getString(); } return *this; } LyXLex & LyXLex::operator>>(docstring & s) { if (isOK()) { next(); s = getDocString(); } return *this; } LyXLex & LyXLex::operator>>(double & s) { if (isOK()) { next(); s = getFloat(); } return *this; } LyXLex & LyXLex::operator>>(int & s) { if (isOK()) { next(); s = getInteger(); } return *this; } LyXLex & LyXLex::operator>>(unsigned int & s) { if (isOK()) { next(); s = getInteger(); } return *this; } LyXLex & LyXLex::operator>>(bool & s) { if (isOK()) { next(); s = getBool(); } return *this; } /// quotes a string, e.g. for use in preferences files or as an argument of the "log" dialog string const LyXLex::quoteString(string const & arg) { std::ostringstream os; os << '"' << subst(subst(arg, "\\", "\\\\"), "\"", "\\\"") << '"'; return os.str(); } } // namespace lyx