/*
- * Copyright (c) [2012-2014] Novell, Inc.
+ * Copyright (c) [2012-2015] Novell, Inc.
*
* All Rights Reserved.
*
}
+int
+operator<(const XFile& lhs, const XFile& rhs)
+{
+ return File::cmp_lt(lhs.name, rhs.name);
+}
+
+
list<XFile>
command_get_xfiles(DBus::Connection& conn, const string& config_name, unsigned int number1,
unsigned int number2)
DBus::Hihi hihi(reply);
hihi >> files;
+ files.sort(); // snapperd can have different locale than client
+ // so sorting is required here
+
return files;
}
int
main(int argc, char** argv)
{
- setlocale(LC_ALL, "");
+ locale::global(locale(""));
setLogDo(&log_do);
setLogQuery(&log_query);
+-------------------------------------------------------------------
+Tue Apr 14 17:58:17 CEST 2015 - aschnell@suse.de
+
+- sort files according to locale
+
-------------------------------------------------------------------
Tue Mar 03 10:22:28 CET 2015 - aschnell@suse.de
/*
- * Copyright (c) [2011-2014] Novell, Inc.
+ * Copyright (c) [2011-2015] Novell, Inc.
*
* All Rights Reserved.
*
#include <fnmatch.h>
#include <errno.h>
#include <fcntl.h>
+#include <locale>
#include <boost/algorithm/string.hpp>
#include "snapper/File.h"
}
- struct FilterHelper
+ void
+ Files::filter(const vector<string>& ignore_patterns)
{
- FilterHelper(const vector<string>& patterns)
- : patterns(patterns) {}
- bool operator()(const File& file)
- {
- for (vector<string>::const_iterator it = patterns.begin(); it != patterns.end(); ++it)
- if (fnmatch(it->c_str(), file.getName().c_str(), FNM_LEADING_DIR) == 0)
- return true;
- return false;
- }
- const vector<string>& patterns;
- };
+ std::function<bool(const File&)> pred = [&ignore_patterns](const File& file) {
+ for (const string& ignore_pattern : ignore_patterns)
+ if (fnmatch(ignore_pattern.c_str(), file.getName().c_str(), FNM_LEADING_DIR) == 0)
+ return true;
+ return false;
+ };
+ entries.erase(remove_if(entries.begin(), entries.end(), pred), entries.end());
+ }
- void
- Files::filter(const vector<string>& ignore_patterns)
+
+ bool
+ File::cmp_lt(const string& lhs, const string& rhs)
{
- entries.erase(remove_if(entries.begin(), entries.end(), FilterHelper(ignore_patterns)),
- entries.end());
+ const std::collate<char>& c = std::use_facet<std::collate<char>>(std::locale());
+
+ return c.compare(lhs.c_str(), lhs.c_str() + lhs.length(),
+ rhs.c_str(), rhs.c_str() + rhs.length()) < 0;
}
- int
- operator<(const File& a, const File& b)
+ bool
+ operator<(const File& lhs, const File& rhs)
{
- return a.getName() < b.getName();
+ return File::cmp_lt(lhs.getName(), rhs.getName());
}
bool
- file_name_less(const File& file, const string& name)
+ operator<(const File& file, const string& name)
{
- return file.getName() < name;
+ return File::cmp_lt(file.getName(), name);
}
Files::iterator
Files::find(const string& name)
{
- iterator ret = lower_bound(entries.begin(), entries.end(), name, file_name_less);
+ iterator ret = lower_bound(entries.begin(), entries.end(), name);
return (ret != end() && ret->getName() == name) ? ret : end();
}
Files::const_iterator
Files::find(const string& name) const
{
- const_iterator ret = lower_bound(entries.begin(), entries.end(), name, file_name_less);
+ const_iterator ret = lower_bound(entries.begin(), entries.end(), name);
return (ret != end() && ret->getName() == name) ? ret : end();
}
/*
- * Copyright (c) [2011-2014] Novell, Inc.
+ * Copyright (c) [2011-2015] Novell, Inc.
*
* All Rights Reserved.
*
XAUndoStatistic getXAUndoStatistic() const;
+ // C++ locale aware less-than comparison
+ static bool cmp_lt(const string& lhs, const string& rhs);
+
private:
bool createParentDirectories(const string& path) const;
LDADD = ../snapper/libsnapper.la ../dbus/libdbus.la -lboost_unit_test_framework
check_PROGRAMS = sysconfig-get1.test dirname1.test basename1.test \
- equal-date.test dbus-escape.test
+ equal-date.test dbus-escape.test cmp-lt.test
TESTS = $(check_PROGRAMS)
--- /dev/null
+
+#define BOOST_TEST_DYN_LINK
+#define BOOST_TEST_MODULE snapper
+
+#include <locale>
+#include <boost/test/unit_test.hpp>
+
+#include <snapper/File.h>
+
+using namespace snapper;
+
+
+namespace std
+{
+ std::ostream&
+ operator<<(std::ostream& s, const vector<string>& v)
+ {
+ for(std::vector<string>::const_iterator it = v.begin(); it != v.end(); ++it)
+ {
+ if (it != v.begin())
+ s << " ";
+ s << *it;
+ }
+
+ return s;
+ }
+}
+
+
+BOOST_AUTO_TEST_CASE(test1)
+{
+ std::locale::global(std::locale("C"));
+
+ vector<string> v = { "A", "B", "b", "a" };
+ sort(v.begin(), v.end(), File::cmp_lt);
+
+ BOOST_CHECK_EQUAL(v, vector<string>({ "A", "B", "a", "b" }));
+}
+
+
+BOOST_AUTO_TEST_CASE(test2)
+{
+ std::locale::global(std::locale("en_US.UTF-8"));
+
+ vector<string> v = { "A", "B", "b", "a" };
+ sort(v.begin(), v.end(), File::cmp_lt);
+
+ BOOST_CHECK_EQUAL(v, vector<string>({ "a", "A", "b", "B" }));
+}
+
+
+BOOST_AUTO_TEST_CASE(test3)
+{
+ std::locale::global(std::locale("de_DE.UTF-8"));
+
+ vector<string> v = { "a", "b", "ä" };
+ sort(v.begin(), v.end(), File::cmp_lt);
+
+ BOOST_CHECK_EQUAL(v, vector<string>({ "a", "ä", "b" }));
+}
+
+
+BOOST_AUTO_TEST_CASE(test4)
+{
+ std::locale::global(std::locale("en_US.UTF-8"));
+
+ vector<string> v = { "a", "\344" }; // invalid UTF-8
+ sort(v.begin(), v.end(), File::cmp_lt);
+
+ BOOST_CHECK_EQUAL(v, vector<string>({ "\344", "a" }));
+}