From ca2fefb8796559b592d1ffd50c8346dcbcb33402 Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Tue, 11 Nov 2014 18:50:11 +0200 Subject: Add a function to compare version number strings Change-Id: I88d3d9040f70e84752ade19001a699f60e9e7636 --- comphelper/Library_comphelper.mk | 1 + comphelper/qa/string/test_string.cxx | 40 ++++++++++++++ comphelper/source/misc/compareversionstrings.cxx | 70 ++++++++++++++++++++++++ include/comphelper/string.hxx | 9 +++ 4 files changed, 120 insertions(+) create mode 100644 comphelper/source/misc/compareversionstrings.cxx diff --git a/comphelper/Library_comphelper.mk b/comphelper/Library_comphelper.mk index 84bf6988ffb4..271a95bc5a6e 100644 --- a/comphelper/Library_comphelper.mk +++ b/comphelper/Library_comphelper.mk @@ -75,6 +75,7 @@ $(eval $(call gb_Library_add_exception_objects,comphelper,\ comphelper/source/misc/accimplaccess \ comphelper/source/misc/anytostring \ comphelper/source/misc/asyncnotification \ + comphelper/source/misc/compareversionstrings \ comphelper/source/misc/comphelper_module \ comphelper/source/misc/comphelper_services \ comphelper/source/misc/componentbase \ diff --git a/comphelper/qa/string/test_string.cxx b/comphelper/qa/string/test_string.cxx index 78137a1052fa..5e9f23ffb087 100644 --- a/comphelper/qa/string/test_string.cxx +++ b/comphelper/qa/string/test_string.cxx @@ -44,6 +44,7 @@ public: void testIsdigitAsciiString(); void testReverseString(); void testEqualsString(); + void testCompareVersionStrings(); CPPUNIT_TEST_SUITE(TestString); CPPUNIT_TEST(testNatural); @@ -57,6 +58,7 @@ public: CPPUNIT_TEST(testIsdigitAsciiString); CPPUNIT_TEST(testReverseString); CPPUNIT_TEST(testEqualsString); + CPPUNIT_TEST(testCompareVersionStrings); CPPUNIT_TEST_SUITE_END(); }; @@ -407,6 +409,44 @@ void TestString::testEqualsString() CPPUNIT_ASSERT(!::comphelper::string::equals(aIn, 'A')); } +int sign(int n) +{ + if (n == 0) + return 0; + if (n < 0) + return -1; + else + return 1; +} + +void TestString::testCompareVersionStrings() +{ +#ifdef TEST +#error TEST already defined +#endif +#define TEST(a,b,result) \ + CPPUNIT_ASSERT(sign(::comphelper::string::compareVersionStrings(a, b)) == result); \ + if ( result != 0 ) \ + CPPUNIT_ASSERT(sign(::comphelper::string::compareVersionStrings(b, a)) == -(result)) + + TEST("", "", 0); + TEST("", "0", -1); + TEST("", "a", -1); + TEST("0", "1", -1); + TEST("1", "2", -1); + TEST("2", "10", -1); + TEST("01", "1", -1); + TEST("01", "001", 1); + TEST("1.00", "1", 1); + TEST("1.2", "1", 1); + TEST("1.01", "1.1", -1); + TEST("1.001", "1.1", -1); + TEST("1.001", "1.010", -1); + TEST("1.2.a", "1.2.b", -1); + +#undef TEST +} + CPPUNIT_TEST_SUITE_REGISTRATION(TestString); } diff --git a/comphelper/source/misc/compareversionstrings.cxx b/comphelper/source/misc/compareversionstrings.cxx new file mode 100644 index 000000000000..cc8cb440733e --- /dev/null +++ b/comphelper/source/misc/compareversionstrings.cxx @@ -0,0 +1,70 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include +#include +#include + +#include +#include + +namespace comphelper { namespace string { + +namespace { + +// BSD licensed, from http://git.musl-libc.org/cgit/musl/plain/src/string/strverscmp.c + +int strverscmp(const char *l, const char *r) +{ + int haszero=1; + while (*l==*r) { + if (!*l) return 0; + + if (*l=='0') { + if (haszero==1) { + haszero=0; + } + } else if (isdigit(*l)) { + if (haszero==1) { + haszero=2; + } + } else { + haszero=1; + } + l++; r++; + } + if (haszero==1 && (*l=='0' || *r=='0')) { + haszero=0; + } + if ((isdigit(*l) && isdigit(*r) ) && haszero) { + size_t lenl=0, lenr=0; + while (isdigit(l[lenl]) ) lenl++; + while (isdigit(r[lenr]) ) lenr++; + if (lenl==lenr) { + return (*l - *r); + } else if (lenl>lenr) { + return 1; + } else { + return -1; + } + } else { + return (*l - *r); + } +} + +} // anonymous namespace + +int compareVersionStrings(const OUString& a, const OUString& b) +{ + return strverscmp(OUStringToOString(a, RTL_TEXTENCODING_UTF8).getStr(), OUStringToOString(b, RTL_TEXTENCODING_UTF8).getStr()); +} + +} } + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/comphelper/string.hxx b/include/comphelper/string.hxx index 74bc6a11ae0f..b062d7cd2677 100644 --- a/include/comphelper/string.hxx +++ b/include/comphelper/string.hxx @@ -463,6 +463,15 @@ inline bool isalnumAscii(sal_Unicode c) return isalphaAscii(c) || isdigitAscii(c); } +/** Compare two strings containing software version numbers + + Inspired by the GNU strverscmp(), but there is no guarantee that the exact + same semantics are used, or that the semantics are stable between LibreOffice versions. + + @return -1, 0 or 1 +*/ +COMPHELPER_DLLPUBLIC int compareVersionStrings(const OUString& a, const OUString& b); + } } #endif -- cgit