]> git.lyx.org Git - features.git/commitdiff
Fix bug 3293 by Bernhard Roider:
authorAbdelrazak Younes <younes@lyx.org>
Mon, 26 Mar 2007 13:43:49 +0000 (13:43 +0000)
committerAbdelrazak Younes <younes@lyx.org>
Mon, 26 Mar 2007 13:43:49 +0000 (13:43 +0000)
This changes the semantics of isOK() and operator(), comments from Bernhard below:

With the old version of lyxlex it was _impossible_ to check whether reading an integer, float, ... succeeded or not. The current solution to check for is.bad() in some cases and in other cases use is.good() does not give the desired information. Moreover the result of is.bad() depends on the stl implementation and behaves different for linux and windows.

the bug was introduced by the patch that fixed the bug that crashed lyx when "inset-insert ert" was executed from the command buffer.
The lexer has the method isOK() which reflects the status of the stream is.
The operators void* and ! are not really well defined (they depend on the value of is.bad()). What is missing is a test if the last reading operation was successful and thus the returned value is valid.
That's what i implemented in this patch.

The new rule for using the lexer:

if you want to know if the lexer still has data to read (either from the stream or from the pushed token) then use "lex.isOK()".
If you want to test if the last reading operation was successful then use eg. "if (lex) {...}" or unsuccessful then use eg. "if (!lex) {...}"

an example:

int readParam(LyxLex &lex) {

    int param = 1; // default value
    if (lex.isOK()) { // the lexer has data to read
        int p;    // temporary variable
        lex >> p;
        if (lex) param = p; // only use the input if the reading operation was successful
    }
    return param;
}

git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@17569 a592a061-630c-0410-9148-cb99ea01b6c8

14 files changed:
src/ToolbarBackend.C
src/buffer.C
src/dociterator.C
src/frontends/controllers/ControlLog.C
src/frontends/controllers/ControlParagraph.C
src/insets/insetbox.C
src/insets/insetert.C
src/insets/insetnote.C
src/insets/insettabular.C
src/insets/insetvspace.C
src/lyxlex.C
src/lyxlex.h
src/lyxlex_pimpl.C
src/lyxlex_pimpl.h

index b12fed44df1b0f956d33e2acc45285935a02072b..c218f1dfebb45ae89ecc3917fc5f139a4ff3509b 100644 (file)
@@ -79,12 +79,12 @@ void ToolbarBackend::read(LyXLex & lex)
        Toolbar tb;
        tb.name = lex.getString();
        lex.next(true);
-       if (!lex.isOK()) {
+       tb.gui_name = lex.getString();
+       if (!lex) {
                lyxerr << "ToolbarBackend::read: Malformed toolbar "
                        "description " <<  lex.getString() << endl;
                return;
        }
-       tb.gui_name = lex.getString();
 
        bool quit = false;
 
index c58b57bafb9085bc90fbe069bc14d7bd384075de..44de4e6cbc469ecd8b152ee0cb6bfbbe250572ea 100644 (file)
@@ -653,7 +653,7 @@ Buffer::ReadStatus Buffer::readFile(LyXLex & lex, FileName const & filename,
        lex.next();
        string const token(lex.getString());
 
-       if (!lex.isOK()) {
+       if (!lex) {
                Alert::error(_("Document could not be read"),
                             bformat(_("%1$s could not be read."), from_utf8(filename.absFilename())));
                return failure;
index ad96095022b2ebbc6b2340bd8bee89b2ff565897..331915982ff8d58f857d8ac37400b42741e1f883 100644 (file)
@@ -234,14 +234,14 @@ DocIterator::col_type DocIterator::col() const
 
 MathArray const & DocIterator::cell() const
 {
-       BOOST_ASSERT(inMathed());
+//     BOOST_ASSERT(inMathed());
        return top().cell();
 }
 
 
 MathArray & DocIterator::cell()
 {
-       BOOST_ASSERT(inMathed());
+//     BOOST_ASSERT(inMathed());
        return top().cell();
 }
 
index 8a6ba4f74c31f449cb41f5caa181b3ee46e117ed..45f0413f23bb33aa2bf092b04379bdb876c73083 100644 (file)
@@ -43,7 +43,7 @@ bool ControlLog::initialiseParams(string const & data)
 
        string logtype, logfile;
        lex >> logtype;
-       if (lex.isOK()) {
+       if (lex) {
                lex.next(true);
                logfile = lex.getString();
        }
index dedbff8ff568def3e87b621f188d2a9c8d9b4faf..47f83b3d0dd16fa272d69fa3068efddfeef7f26f 100644 (file)
@@ -53,7 +53,12 @@ bool ControlParagraph::initialiseParams(string const & data)
                } else if (token == "update") {
                        lex.next();
                        bool const accept = lex.getBool();
-                       action = accept ? 1 : 2;
+                       if (lex) {
+                               action = accept ? 1 : 2;
+                       } else {
+                               // Unrecognised update option
+                               return false;
+                       }
                } else if (!token.empty()) {
                        // Unrecognised token
                        return false;
index 44b1b3bd6f99c8ae4016a8a4dadfd8862362c512..acc533e4b356b1f95b2455aaf585e2a262b86ed3 100644 (file)
@@ -531,15 +531,17 @@ void InsetBoxParams::read(LyXLex & lex)
        if (!lex.isOK())
                return;
 
-       if (lex.isOK()) {
-               lex.next();
-               type = lex.getString();
-       }
-       if (!lex.isOK())
+       lex.next();
+       type = lex.getString();
+
+       if (!lex)
                return;
+
        lex.next();
        string token;
        token = lex.getString();
+       if (!lex)
+               return;
        if (token == "position") {
                lex.next();
                // The [0] is needed. We need the first and only char in
@@ -549,10 +551,11 @@ void InsetBoxParams::read(LyXLex & lex)
                lyxerr << "InsetBox::Read: Missing 'position'-tag!" << token << endl;
                lex.pushToken(token);
        }
-       if (!lex.isOK())
-               return;
+
        lex.next();
        token = lex.getString();
+       if (!lex)
+               return;
        if (token == "hor_pos") {
                lex.next();
                hor_pos = lex.getString()[0];
@@ -560,10 +563,11 @@ void InsetBoxParams::read(LyXLex & lex)
                lyxerr << "InsetBox::Read: Missing 'hor_pos'-tag!" << token << endl;
                lex.pushToken(token);
        }
-       if (!lex.isOK())
-               return;
+
        lex.next();
        token = lex.getString();
+       if (!lex)
+               return;
        if (token == "has_inner_box") {
                lex.next();
                inner_box = lex.getInteger();
@@ -572,10 +576,10 @@ void InsetBoxParams::read(LyXLex & lex)
                lex.pushToken(token);
        }
 
-       if (!lex.isOK())
-               return;
        lex.next();
        token = lex.getString();
+       if (!lex)
+               return;
        if (token == "inner_pos") {
                lex.next();
                inner_pos = lex.getString()[0];
@@ -584,10 +588,11 @@ void InsetBoxParams::read(LyXLex & lex)
                        << token << endl;
                lex.pushToken(token);
        }
-       if (!lex.isOK())
-               return;
+
        lex.next();
        token = lex.getString();
+       if (!lex)
+               return;
        if (token == "use_parbox") {
                lex.next();
                use_parbox = lex.getInteger();
@@ -595,10 +600,11 @@ void InsetBoxParams::read(LyXLex & lex)
                lyxerr << "InsetBox::Read: Missing 'use_parbox'-tag!" << endl;
                lex.pushToken(token);
        }
-       if (!lex.isOK())
-               return;
+
        lex.next();
        token = lex.getString();
+       if (!lex)
+               return;
        if (token == "width") {
                lex.next();
                width = LyXLength(lex.getString());
@@ -606,10 +612,11 @@ void InsetBoxParams::read(LyXLex & lex)
                lyxerr << "InsetBox::Read: Missing 'width'-tag!" << endl;
                lex.pushToken(token);
        }
-       if (!lex.isOK())
-               return;
+
        lex.next();
        token = lex.getString();
+       if (!lex)
+               return;
        if (token == "special") {
                lex.next();
                special = lex.getString();
@@ -617,10 +624,11 @@ void InsetBoxParams::read(LyXLex & lex)
                lyxerr << "InsetBox::Read: Missing 'special'-tag!" << endl;
                lex.pushToken(token);
        }
-       if (!lex.isOK())
-               return;
+
        lex.next();
        token = lex.getString();
+       if (!lex)
+               return;
        if (token == "height") {
                lex.next();
                height = LyXLength(lex.getString());
@@ -628,10 +636,11 @@ void InsetBoxParams::read(LyXLex & lex)
                lyxerr << "InsetBox::Read: Missing 'height'-tag!" << endl;
                lex.pushToken(token);
        }
-       if (!lex.isOK())
-               return;
+
        lex.next();
        token = lex.getString();
+       if (!lex)
+               return;
        if (token == "height_special") {
                lex.next();
                height_special = lex.getString();
index 091a2427f15427cc4b0867c78845b08db834f8c5..cb62a2579b4290e7b6236371c5609daa868d2191 100644 (file)
@@ -466,7 +466,7 @@ void InsetERTMailer::string2params(string const & in,
 
        int s;
        lex >> s;
-       if (lex.isOK())
+       if (lex)
                status = static_cast<InsetCollapsable::CollapseStatus>(s);
 }
 
index 38250c38af6004c44fd9ff7cc6bf8c0430587b8e..f2cfd7477966dece99e1a613001372fde1c7dc42 100644 (file)
@@ -105,7 +105,7 @@ void InsetNoteParams::read(LyXLex & lex)
 {
        string label;
        lex >> label;
-       if (lex.isOK())
+       if (lex)
                type = notetranslator().find(label);
 }
 
index bd9b9dff057a65fbf0d9767110f2fa91040f69a8..a3ab7560c14d04eef2a3200daf3facdc569f347d 100644 (file)
@@ -231,11 +231,11 @@ void InsetTabular::read(Buffer const & buf, LyXLex & lex)
 
        lex.next();
        string token = lex.getString();
-       while (lex.isOK() && (token != "\\end_inset")) {
+       while (lex && token != "\\end_inset") {
                lex.next();
                token = lex.getString();
        }
-       if (token != "\\end_inset") {
+       if (!lex) {
                lex.printError("Missing \\end_inset at this point. "
                               "Read: `$$Token'");
        }
index 789b75c585f5be64795cb03464d492cd411bea1d..72e152d0181c33847f7901cda5148fcb2c62e231 100644 (file)
@@ -88,7 +88,7 @@ void InsetVSpace::read(Buffer const &, LyXLex & lex)
        BOOST_ASSERT(lex.isOK());
        string vsp;
        lex >> vsp;
-       if (lex.isOK())
+       if (lex)
                space_ = VSpace(vsp);
 
        string end_token;
@@ -257,7 +257,7 @@ void InsetVSpaceMailer::string2params(string const & in, VSpace & vspace)
 
        string vsp;
        lex >> vsp;
-       if (lex.isOK())
+       if (lex)
                vspace = VSpace(vsp);
 }
 
index edb0896be26dd3ec0582ee8473aa76739f5d1633..1665d38f459cba27f9a1df89e44b16d06cbd6550 100644 (file)
@@ -53,7 +53,7 @@ LyXLex::~LyXLex()
 
 bool LyXLex::isOK() const
 {
-       return pimpl_->is.good();
+       return pimpl_->inputAvailable();
 }
 
 
@@ -124,8 +124,16 @@ int LyXLex::lex()
 
 int LyXLex::getInteger() const
 {
+       lastReadOk_ = pimpl_->status == LEX_DATA || pimpl_->status == LEX_TOKEN;
+       if (!lastReadOk_) {
+               pimpl_->printError("integer token missing");
+               return -1;
+       }
+
        if (isStrInt(pimpl_->getString()))
                return convert<int>(pimpl_->getString());
+
+       lastReadOk_ = false;
        pimpl_->printError("Bad integer `$$Token'");
        return -1;
 }
@@ -136,9 +144,17 @@ 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).
+       lastReadOk_ = pimpl_->status == LEX_DATA || pimpl_->status == LEX_TOKEN;
+       if (!lastReadOk_) {
+               pimpl_->printError("float token missing");
+               return -1;
+       }
+
        string const str = subst(pimpl_->getString(), ",", ".");
        if (isStrDbl(str))
                return convert<double>(str);
+
+       lastReadOk_ = false;
        pimpl_->printError("Bad float `$$Token'");
        return -1;
 }
@@ -146,13 +162,23 @@ double LyXLex::getFloat() const
 
 string const LyXLex::getString() const
 {
+       lastReadOk_ = pimpl_->status == LEX_DATA || pimpl_->status == LEX_TOKEN;
+
+       if (lastReadOk_)
        return pimpl_->getString();
+
+       return string();
 }
 
 
 docstring const LyXLex::getDocString() const
 {
-       return pimpl_->getDocString();
+       lastReadOk_ = pimpl_->status == LEX_DATA || pimpl_->status == LEX_TOKEN;
+       
+       if (lastReadOk_)
+               return pimpl_->getDocString();
+
+       return docstring();
 }
 
 
@@ -164,7 +190,7 @@ string const LyXLex::getLongString(string const & endtoken)
        string str, prefix;
        bool firstline = true;
 
-       while (isOK()) {
+       while (pimpl_->is) { //< eatLine only reads from is, not from pushTok
                if (!eatLine())
                        // blank line in the file being read
                        continue;
@@ -197,7 +223,7 @@ string const LyXLex::getLongString(string const & endtoken)
                str += ltrim(tmpstr, "\t") + '\n';
        }
 
-       if (!isOK()) {
+       if (!pimpl_->is) {
                printError("Long string not ended by `" + endtoken + '\'');
        }
 
@@ -208,11 +234,14 @@ string const LyXLex::getLongString(string const & endtoken)
 bool LyXLex::getBool() const
 {
        if (pimpl_->getString() == "true") {
+               lastReadOk_ = true;
                return true;
        } else if (pimpl_->getString() != "false") {
                pimpl_->printError("Bad boolean `$$Token'. "
                                   "Use \"false\" or \"true\"");
+               lastReadOk_ = false;
        }
+       lastReadOk_ = true;
        return false;
 }
 
@@ -246,13 +275,13 @@ LyXLex::operator void const *() const
        // 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;
+       return lastReadOk_? this: 0;
 }
 
 
 bool LyXLex::operator!() const
 {
-       return pimpl_->is.bad();
+       return !lastReadOk_;
 }
 
 
@@ -261,6 +290,8 @@ LyXLex & LyXLex::operator>>(std::string & s)
        if (isOK()) {
                next();
                s = getString();
+       } else {
+               lastReadOk_ = false;
        }
        return *this;
 }
@@ -271,6 +302,8 @@ LyXLex & LyXLex::operator>>(docstring & s)
        if (isOK()) {
                next();
                s = getDocString();
+       } else {
+               lastReadOk_ = false;
        }
        return *this;
 }
@@ -281,6 +314,8 @@ LyXLex & LyXLex::operator>>(double & s)
        if (isOK()) {
                next();
                s = getFloat();
+       } else {
+               lastReadOk_ = false;
        }
        return *this;
 }
@@ -291,6 +326,8 @@ LyXLex & LyXLex::operator>>(int & s)
        if (isOK()) {
                next();
                s = getInteger();
+       } else {
+               lastReadOk_ = false;
        }
        return *this;
 }
@@ -301,6 +338,8 @@ LyXLex & LyXLex::operator>>(unsigned int & s)
        if (isOK()) {
                next();
                s = getInteger();
+       } else {
+               lastReadOk_ = false;
        }
        return *this;
 }
@@ -311,6 +350,8 @@ LyXLex & LyXLex::operator>>(bool & s)
        if (isOK()) {
                next();
                s = getBool();
+       } else {
+               lastReadOk_ = false;
        }
        return *this;
 }
index 0c1469a9eec86c6e541bbe803f6601f35992400f..155aa380f0cb4bf1cec07ef6fd0ed33a2195ef17 100644 (file)
@@ -37,8 +37,22 @@ struct keyword_item {
 };
 
 /** Generalized simple lexical analizer.
-    It can be used for simple syntax parsers, like lyxrc,
-    texclass and others to come.
+       Use the method isOK() to check if there is still data available 
+       for lexing. Use one of the the operators void* or ! to test if
+       the last reading operation was successful.
+       
+       Example:
+
+       int readParam(LyxLex &lex) {
+               int param = 1; // default value
+               if (lex.isOK()) { // the lexer has data to read
+                       int p;    // temporary variable
+                       lex >> p;
+                       if (lex) param = p; // only use the input if reading was successful
+               }
+               return param;
+       } 
+
     @see lyxrc.C for an example of usage.
   */
 class LyXLex : boost::noncopyable {
@@ -61,14 +75,16 @@ public:
        };
 
        /// stream is open and end of stream is not reached
-       /// FIXME: Rename to good() since this is the name of the
-       /// corresponding std::stream method.
+       /// FIXME: test also if pushTok is not empty
+       /// FIXME: the method should be renamed to something like 
+       ///        dataAvailable(), in order to reflect the real behavior
        bool isOK() const;
-       /// stream is ok
-       /// FIXME: This does not behave like the std::stream counterpart.
+       /// FIXME: The next two operators should be replaced by one method
+       ///        called e.g. lastReadOk(), in order to reflect the real 
+       ///        behavior
+       /// last read operation was successful.
        operator void const *() const;
-       /// stream is not ok
-       /// FIXME: This does not behave like the std::stream counterpart.
+       /// last read operation was not successful
        bool operator!() const;
        /// return true if able to open file, else false
        bool setFile(support::FileName const & filename);
@@ -84,7 +100,7 @@ public:
        /// returns a lex code
        int lex();
 
-       /** Just read athe next word. If esc is true remember that
+       /** Just read the next word. If esc is true remember that
            some chars might be escaped: "\ atleast
        */
        bool next(bool esc = false);
@@ -162,6 +178,8 @@ private:
        class Pimpl;
        ///
        Pimpl * pimpl_;
+       ///
+       mutable bool lastReadOk_;
 };
 
 
index 0ae2b1391c85323f36a6f4d3aef64ef6543879bb..90dcfd9dbde69857241224d9e9aff6477b9aa64f 100644 (file)
@@ -204,15 +204,15 @@ bool LyXLex::Pimpl::next(bool esc /* = false */)
                // There can have been a whole line pushed so
                // we extract the first word and leaves the rest
                // in pushTok. (Lgb)
-               if (pushTok.find(' ') != string::npos && pushTok[0] == '\\') {
+               if (pushTok[0] == '\\' && pushTok.find(' ') != string::npos) {
                        buff.clear();
                        pushTok = split(pushTok, buff, ' ');
-                       return true;
                } else {
                        buff = pushTok;
                        pushTok.clear();
-                       return true;
                }
+               status = LEX_TOKEN;
+               return true;
        }
        if (!esc) {
                unsigned char c = 0; // getc() returns an int
@@ -306,26 +306,8 @@ bool LyXLex::Pimpl::next(bool esc /* = false */)
                        c = cc;
 
                        // skip ','s
-                       if (c == ',') continue;
-
-                       if (c == '\\') {
-                               // escape
-                               buff.clear();
-
-                               do {
-                                       if (c == '\\') {
-                                               // escape the next char
-                                               is.get(cc);
-                                               c = cc;
-                                       }
-                                       buff.push_back(c);
-                                       is.get(cc);
-                                       c = cc;
-                               } while (c > ' ' && c != ',' && is);
-
-                               status = LEX_TOKEN;
+                       if (c == ',') 
                                continue;
-                       }
 
                        if (c == commentChar) {
                                // Read rest of line (fast :-)
@@ -457,6 +439,9 @@ bool LyXLex::Pimpl::eatLine()
                buff.resize(buff.size() - 1);
                status = LEX_DATA;
                return true;
+       } else if (buff.length() > 0) { // last line
+               status = LEX_DATA;
+               return true;
        } else {
                return false;
        }
@@ -469,15 +454,15 @@ bool LyXLex::Pimpl::nextToken()
                // There can have been a whole line pushed so
                // we extract the first word and leaves the rest
                // in pushTok. (Lgb)
-               if (pushTok.find(' ') != string::npos && pushTok[0] == '\\') {
+               if (pushTok[0] == '\\' && pushTok.find(' ') != string::npos) {
                        buff.clear();
                        pushTok = split(pushTok, buff, ' ');
-                       return true;
                } else {
                        buff = pushTok;
                        pushTok.clear();
-                       return true;
                }
+               status = LEX_TOKEN;
+               return true;
        }
 
        status = 0;
@@ -519,6 +504,11 @@ bool LyXLex::Pimpl::nextToken()
 }
 
 
+bool LyXLex::Pimpl::inputAvailable() {
+       return is.good(); 
+}
+
+
 void LyXLex::Pimpl::pushToken(string const & pt)
 {
        pushTok = pt;
index c844fb4c1ca56d4a3baecdd5d44d1032e8250c4d..7fe3905b293b8d3d883b51d280e286856fbd5e3e 100644 (file)
@@ -65,6 +65,8 @@ public:
        bool eatLine();
        ///
        bool nextToken();
+       /// test if there is a pushed token or the stream is ok
+       bool inputAvailable();
        ///
        void pushToken(std::string const &);
        /// fb_ is only used to open files, the stream is accessed through is.