/*************************************************************************************************** ** ** Copyright (C) 2016 Roman Telezhynskyi ** ** Permission is hereby granted, free of charge, to any person obtaining a copy of this ** software and associated documentation files (the "Software"), to deal in the Software ** without restriction, including without limitation the rights to use, copy, modify, ** merge, publish, distribute, sublicense, and/or sell copies of the Software, and to ** permit persons to whom the Software is furnished to do so, subject to the following conditions: ** ** The above copyright notice and this permission notice shall be included in all copies or ** substantial portions of the Software. ** ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT ** NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, ** DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ** ******************************************************************************************************/ #include "qmudef.h" #include #include enum State { Init = 0, Sign = 1, Thousand = 2, Mantissa = 3, Dot = 4, Abscissa = 5, ExpMark = 6, ExpSign = 7, Exponent = 8, Done = 9 }; enum InputToken { InputSign = 1, InputThousand = 2, InputDigit = 3, InputDot = 4, InputExp = 5 }; static const QChar QmuEOF = QChar(static_cast(0xffff)); //guaranteed not to be a character. //--------------------------------------------------------------------------------------------------------------------- static QChar GetChar(const QString &formula, int &index) { if (index >= formula.size()) { return QmuEOF; } return formula.at(index++); } //--------------------------------------------------------------------------------------------------------------------- static QChar EatWhiteSpace(const QString &formula, int &index) { QChar c; do { c = GetChar(formula, index); } while ( c != QmuEOF && c.isSpace() ); return c; } //--------------------------------------------------------------------------------------------------------------------- static int CheckChar(QChar &c, const QLocale &locale, const QChar &decimal, const QChar &thousand) { INIT_LOCALE_VARIABLES(locale); if (c == positiveSign) { c = '+'; return InputToken::InputSign; } else if (c == negativeSign) { c = '-'; return InputToken::InputSign; } else if (c == sign0) { c = '0'; return InputToken::InputDigit; } else if (c == sign1) { c = '1'; return InputToken::InputDigit; } else if (c == sign2) { c = '2'; return InputToken::InputDigit; } else if (c == sign3) { c = '3'; return InputToken::InputDigit; } else if (c == sign4) { c = '4'; return InputToken::InputDigit; } else if (c == sign5) { c = '5'; return InputToken::InputDigit; } else if (c == sign6) { c = '6'; return InputToken::InputDigit; } else if (c == sign7) { c = '7'; return InputToken::InputDigit; } else if (c == sign8) { c = '8'; return InputToken::InputDigit; } else if (c == sign9) { c = '9'; return InputToken::InputDigit; } else if (c == decimal) { return InputToken::InputDot; } else if (c == thousand) { return InputToken::InputThousand; } else if (c == expLower) { c = 'e'; return InputToken::InputExp; } else if (c == expUpper) { c = 'E'; return InputToken::InputExp; } else { return 0; } return 0; } //--------------------------------------------------------------------------------------------------------------------- int ReadVal(const QString &formula, qreal &val, const QLocale &locale, const QChar &decimal, const QChar &thousand) { // Must not be equal if (decimal == thousand || formula.isEmpty()) { val = 0; return -1; } INIT_LOCALE_VARIABLES(locale); QSet reserved; reserved << positiveSign << negativeSign << sign0 << sign1 << sign2 << sign3 << sign4 << sign5 << sign6 << sign7 << sign8 << sign9 << expUpper << expLower; if (reserved.contains(decimal) || reserved.contains(thousand)) { val = 0; return -1; } // row - current state, column - new state static uchar table[9][6] = { /* None InputSign InputThousand InputDigit InputDot InputExp */ { 0, State::Sign, 0, State::Mantissa, State::Dot, 0, }, // Init { 0, 0, 0, State::Mantissa, State::Dot, 0, }, // Sign { 0, 0, 0, State::Mantissa, 0, 0, }, // Thousand { State::Done, State::Done, State::Thousand, State::Mantissa, State::Dot, State::ExpMark,}, // Mantissa { 0, 0, 0, State::Abscissa, 0, 0, }, // Dot { State::Done, State::Done, 0, State::Abscissa, 0, State::ExpMark,}, // Abscissa { 0, State::ExpSign, 0, State::Exponent, 0, 0, }, // ExpMark { 0, 0, 0, State::Exponent, 0, 0, }, // ExpSign { State::Done, 0, 0, State::Exponent, 0, State::Done } // Exponent }; int state = State::Init; // parse state int input; // input token QString buf; int index = 0; // start position QChar c = EatWhiteSpace(formula, index); while ( true ) { input = CheckChar(c, locale, decimal, thousand); state = table[state][input]; if (state == 0) { val = 0; return -1; } else if (state == Done) { // Convert to C locale QLocale cLocale(QLocale::C); const QChar cDecimal = cLocale.decimalPoint(); const QChar cThousand = cLocale.groupSeparator(); if (locale != cLocale && (cDecimal != decimal || cThousand != thousand)) { if (decimal == cThousand) {// Handle reverse to C locale case: thousand '.', decimal ',' const QChar tmpThousand = '@'; buf.replace(thousand, tmpThousand); buf.replace(decimal, cDecimal); buf.replace(tmpThousand, cThousand); } else { buf.replace(thousand, cThousand); buf.replace(decimal, cDecimal); } } bool ok = false; const double d = cLocale.toDouble(buf, &ok); if (ok) { val = d; return buf.size(); } else { val = 0; return -1; } } buf.append(c); c = GetChar(formula, index); } return -1; }