Commit dff65016 authored by Chusslove Illich's avatar Chusslove Illich
Browse files

Usage of atof() to parse floats in trader language was locale-dependent:

if locale specified something other than dot as decimal separator,
parsing floats (which are always dot-separated in queries) failed.
Replaced atof() with simple sufficient custom parser.

Added a unit test.

BUG: 275548
FIXED-IN: 4.7.1
(cherry picked from commit d522bb4d)
parent bff42dbf
......@@ -9,6 +9,7 @@
char* KTraderParse_putSymbol( char *_name );
char *KTraderParse_putSymbolInBrackets( char *_name );
char* KTraderParse_putString( char *_name );
double KTraderParse_putSimplePositiveFloat( char *_name );
int yywrap();
int kiotraderlex(YYSTYPE * yylval, yyscan_t scanner);
void KTraderParse_initFlex( const char *_code, yyscan_t _scanner );
......@@ -55,7 +56,7 @@ DIGIT [0-9]
"-"{DIGIT}+ { yylval->vali = atoi( yytext ); return VAL_NUM; }
{DIGIT}+ { yylval->vali = atoi( yytext ); return VAL_NUM; }
{DIGIT}*"\."{DIGIT}+ { yylval->vald = atof( yytext ); return VAL_FLOAT; }
{DIGIT}*"\."{DIGIT}+ { yylval->vald = KTraderParse_putSimplePositiveFloat( yytext ); return VAL_FLOAT; }
\[[a-zA-Z][a-zA-Z0-9\-]*\] { yylval->name = KTraderParse_putSymbolInBrackets( yytext ); return VAL_ID; }
......@@ -125,6 +126,35 @@ char* KTraderParse_putString( char *_str )
return p;
}
/* Sufficient replacement for atof() to parse [0-9]*\.[0-9]+
because atof() consults locale for decimal separator,
while we need it always to be the dot. */
double KTraderParse_putSimplePositiveFloat( char *_str )
{
char *p;
int f, g, d;
f = 0;
p = _str;
while ( *p >= '0' && *p <= '9' )
{
f = f * 10 + ( *p - '0' );
p++;
}
if ( *p != '.' )
return (double) f;
p++;
g = 0;
d = 1;
while ( *p >= '0' && *p <= '9' )
{
g = g * 10 + ( *p - '0' );
d *= 10;
p++;
}
return ( (double) ( f * d + g ) ) / d;
}
void KTraderParse_initFlex( const char *_code, yyscan_t _scanner )
{
yy_switch_to_buffer( yy_scan_string( _code, _scanner ), _scanner );
......
......@@ -16,6 +16,8 @@
* Boston, MA 02110-1301, USA.
*/
#include <locale.h>
#include "kservicetest.h"
#include "kservicetest.moc"
#include <qtest_kde.h>
......@@ -38,6 +40,16 @@
void KServiceTest::initTestCase()
{
// A non-C locale is necessary for some tests.
// This locale must have the follwing properties:
// - some character other than dot as decimal separator
// If it cannot be set, locale-dependent tests are skipped.
setlocale(LC_ALL, "fr_FR.utf8");
m_hasNonCLocale = (setlocale(LC_ALL, NULL) == QByteArray("fr_FR.utf8"));
if (!m_hasNonCLocale) {
kDebug() << "Setting locale to fr_FR.utf8 failed";
}
QString profilerc = KStandardDirs::locateLocal( "config", "profilerc" );
if ( !profilerc.isEmpty() )
QFile::remove( profilerc );
......@@ -303,6 +315,13 @@ void KServiceTest::testTraderConstraints()
QCOMPARE(offers.count(), 1);
QVERIFY( offerListHasService( offers, "faketextplugin.desktop" ) );
if (m_hasNonCLocale) {
// Test float parsing, must use dot as decimal separator independent of locale.
offers = KServiceTypeTrader::self()->query("KTextEditor/Plugin", "([X-KDE-Version] > 4.559) and ([X-KDE-Version] < 4.561)");
QCOMPARE(offers.count(), 1);
QVERIFY(offerListHasService( offers, "fakeservice.desktop"));
}
// A test with an invalid query, to test for memleaks
offers = KServiceTypeTrader::self()->query("KTextEditor/Plugin", "A == B OR C == D AND OR Foo == 'Parse Error'");
QVERIFY(offers.isEmpty());
......@@ -501,6 +520,7 @@ void KServiceTest::createFakeService()
group.writeEntry("Name", "FakePlugin");
group.writeEntry("Type", "Service");
group.writeEntry("X-KDE-Library", "fakeservice");
group.writeEntry("X-KDE-Version", "4.56");
group.writeEntry("ServiceTypes", "KTextEditor/Plugin");
group.writeEntry("MimeType", "text/plain;");
}
......
......@@ -52,6 +52,7 @@ private:
QString m_firstOffer;
bool m_hasKde4Konsole;
QAtomicInt m_sycocaUpdateDone;
bool m_hasNonCLocale;
};
#endif
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment