gnucash maint: Multiple changes pushed
John Ralls
jralls at code.gnucash.org
Sun Jan 6 13:13:28 EST 2019
Updated via https://github.com/Gnucash/gnucash/commit/b4fedff9 (commit)
via https://github.com/Gnucash/gnucash/commit/cee97be8 (commit)
from https://github.com/Gnucash/gnucash/commit/793fb1a3 (commit)
commit b4fedff90e8b35e69620922f27376ef78ade6d0e
Author: John Ralls <jralls at ceridwen.us>
Date: Sun Jan 6 09:52:43 2019 -0800
Provide a single static instance of C++ locale.
We can't use std::locale::global because all streams imbue it by
default and if it's not 'C' (aka std::locale::classic) then we
must imbue all the streams that we don't want localized, and that's
most of them.
Provides error checking for setting the C++ locale from the environment.
This is necessary both because the environment might have an invalid
locale, which would cause an unhandled exception crash.
On windows std::locale("") can't handle some Microsoft-style locale
strings (e.g. Spanish_Spain) so we use boost::locale's gen("") function
to set the locale--though even that can't handle a Microsoft-style
locale string with an appended charset (e.g. Spanish_Spain.1252) and
that's what glibc's setlocale(LC_ALL, NULL) emits.
diff --git a/gnucash/gnome/assistant-loan.cpp b/gnucash/gnome/assistant-loan.cpp
index 3509b18..5505623 100644
--- a/gnucash/gnome/assistant-loan.cpp
+++ b/gnucash/gnome/assistant-loan.cpp
@@ -49,6 +49,7 @@ extern "C"
#include "gnc-engine.h"
}
+#include <gnc-locale-utils.hpp>
#include <boost/locale.hpp>
#include <string>
#include <sstream>
@@ -2320,7 +2321,7 @@ struct cust_prec_punct : std::moneypunct_byname<wchar_t, false> {
template<int prec>
std::string to_str_with_prec (const gdouble val)
{
- auto loc = std::locale(std::locale(""), new cust_prec_punct<prec>(""));
+ auto loc = std::locale(gnc_get_locale(), new cust_prec_punct<prec>(""));
std::wstringstream valstr;
valstr.imbue(loc);
valstr << std::put_money(val * pow(10, prec));
diff --git a/gnucash/import-export/csv-imp/assistant-csv-trans-import.cpp b/gnucash/import-export/csv-imp/assistant-csv-trans-import.cpp
index 777caf4..00c1a12 100644
--- a/gnucash/import-export/csv-imp/assistant-csv-trans-import.cpp
+++ b/gnucash/import-export/csv-imp/assistant-csv-trans-import.cpp
@@ -64,6 +64,7 @@ extern "C"
#include "gnc-tokenizer-fw.hpp"
#include "gnc-tokenizer-csv.hpp"
+#include <gnc-locale-utils.hpp>
#include <boost/locale.hpp>
namespace bl = boost::locale;
@@ -2068,7 +2069,7 @@ CsvImpTransAssist::assist_summary_page_prepare ()
try
{
/* Translators: {1} will be replaced with a filename */
- text += (bl::format (bl::translate ("The transactions were imported from file '{1}'.")) % m_file_name).str(gen(""));
+ text += (bl::format (bl::translate ("The transactions were imported from file '{1}'.")) % m_file_name).str(gnc_get_locale());
text += "</b></span>";
}
catch (const bl::conv::conversion_error& err)
diff --git a/libgnucash/core-utils/CMakeLists.txt b/libgnucash/core-utils/CMakeLists.txt
index b08e38b..6d02f48 100644
--- a/libgnucash/core-utils/CMakeLists.txt
+++ b/libgnucash/core-utils/CMakeLists.txt
@@ -25,6 +25,7 @@ set (core_utils_SOURCES
gnc-guile-utils.c
gnc-jalali.c
gnc-locale-utils.c
+ gnc-locale-utils.cpp
gnc-path.c
)
@@ -116,6 +117,7 @@ set(core_utils_noinst_HEADERS
gnc-guile-utils.h
gnc-jalali.h
gnc-locale-utils.h
+ gnc-locale-utils.hpp
gnc-path.h
)
diff --git a/libgnucash/core-utils/gnc-filepath-utils.cpp b/libgnucash/core-utils/gnc-filepath-utils.cpp
index d421bbc..7371534 100644
--- a/libgnucash/core-utils/gnc-filepath-utils.cpp
+++ b/libgnucash/core-utils/gnc-filepath-utils.cpp
@@ -64,6 +64,7 @@ extern "C" {
#endif
}
+#include "gnc-locale-utils.hpp"
#include <boost/filesystem.hpp>
#include <boost/locale.hpp>
#include <iostream>
@@ -587,9 +588,8 @@ static std::string migrate_gnc_datahome()
gen.add_messages_path(gnc_path_get_datadir());
gen.add_messages_domain(PACKAGE);
-// std::locale::global(gen(""));
std::stringstream migration_msg;
- migration_msg.imbue(gen(""));
+ migration_msg.imbue(gnc_get_locale());
/* Step 1: copy directory $HOME/.gnucash to $GNC_DATA_HOME */
auto full_copy = copy_recursive (old_dir, gnc_userdata_home);
diff --git a/libgnucash/core-utils/gnc-locale-utils.cpp b/libgnucash/core-utils/gnc-locale-utils.cpp
new file mode 100644
index 0000000..e3de961
--- /dev/null
+++ b/libgnucash/core-utils/gnc-locale-utils.cpp
@@ -0,0 +1,78 @@
+/********************************************************************\
+ * gnc-locale-utils.cpp -- provide a default locale for C++ *
+ * Copyright (C) 2019 John Ralls <jralls at ceridwen.us *
+ * *
+ * This program is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU General Public License as *
+ * published by the Free Software Foundation; either version 2 of *
+ * the License, or (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License*
+ * along with this program; if not, contact: *
+ * *
+ * Free Software Foundation Voice: +1-617-542-5942 *
+ * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
+ * Boston, MA 02110-1301, USA gnu at gnu.org *
+\********************************************************************/
+
+#include <clocale>
+#include <boost/locale.hpp>
+#include "gnc-locale-utils.hpp"
+
+/* This function addresses two separate problems: First, if we set
+ * std::locale::global then all streams automagically imbue
+ * themselves with it and we have to re-imbue all of the backends and
+ * logging streams with std::locale::classic() so that data and log
+ * files aren't localized. Second, calling std::locale("") is slow,
+ * so we want to do it only once. Worse, the standard C++ library in
+ * Mingw64 chokes on at least some Microsoft-style locale strings
+ * (e.g. "Spanish_Spain") but libc's setlocale(LC_ALL, NULL) emits
+ * them even if originally fed a Unix-style locale ("es_ES").
+ *
+ * The solution is this function which caches the setlocale() locale
+ * the first time it's called and which uses a boost::locale
+ * generator, which does know what to do with (sometimes adjusted)
+ * Microsoft locale strings.
+ */
+const std::locale&
+gnc_get_locale()
+{
+ static std::locale cached;
+ static bool tried_already = false;
+ if (!tried_already)
+ {
+ boost::locale::generator gen;
+ tried_already = true;
+ try
+ {
+ cached = gen("");
+ }
+ catch (const std::runtime_error& err)
+ {
+ std::string c_locale(setlocale(LC_ALL, nullptr));
+ std::cerr << "[gnc_get_locale] Failed to create app-default locale from " << c_locale << " because " << err.what() << "\n";
+ auto dot = c_locale.find(".");
+ if (dot != std::string::npos)
+ {
+ try
+ {
+ cached = gen(c_locale.substr(0, dot));
+ }
+ catch (std::runtime_error& err2)
+ {
+ std::cerr << "[gnc_get_locale] Failed to create app-default locale from " << c_locale << " because " << err.what() << " so using the 'C' locale for C++.\n";
+ }
+ }
+ else
+ {
+ std::cerr << "[gnc_get_locale] Using the 'C' locale for C++\n";
+ }
+ }
+ }
+ return cached;
+}
diff --git a/libgnucash/core-utils/gnc-locale-utils.hpp b/libgnucash/core-utils/gnc-locale-utils.hpp
new file mode 100644
index 0000000..c16467e
--- /dev/null
+++ b/libgnucash/core-utils/gnc-locale-utils.hpp
@@ -0,0 +1,39 @@
+/********************************************************************\
+ * gnc-locale-utils.hpp -- provide a default locale for C++ *
+ * Copyright (C) 2019 John Ralls <jralls at ceridwen.us *
+ * *
+ * This program is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU General Public License as *
+ * published by the Free Software Foundation; either version 2 of *
+ * the License, or (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License*
+ * along with this program; if not, contact: *
+ * *
+ * Free Software Foundation Voice: +1-617-542-5942 *
+ * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
+ * Boston, MA 02110-1301, USA gnu at gnu.org *
+\********************************************************************/
+#ifndef GNC_LOCALE_UTILS_HPP
+#define GNC_LOCALE_UTILS_HPP
+
+#include <locale>
+
+/** Get the default application locale.
+ *
+ * If we set std::locale::global we have to imbue every stream that
+ * we want in the C locale, and that's a lot more than we want imbued
+ * with the application locale. Calling std::locale("") is expensive,
+ * so call this instead.
+ *
+ * @returns A static std::locale representing the one set with
+ * setlocale() in main().
+ */
+const std::locale& gnc_get_locale();
+
+#endif /* GNC_LOCALE_UTILS_HPP */
diff --git a/libgnucash/core-utils/test/CMakeLists.txt b/libgnucash/core-utils/test/CMakeLists.txt
index fe92a2c..3420787 100644
--- a/libgnucash/core-utils/test/CMakeLists.txt
+++ b/libgnucash/core-utils/test/CMakeLists.txt
@@ -46,6 +46,7 @@ set(test_gnc_path_util_SOURCES
${MODULEPATH}/gnc-path.c
${MODULEPATH}/binreloc.c
${MODULEPATH}/gnc-filepath-utils.cpp
+ ${MODULEPATH}/gnc-locale-utils.cpp
gtest-path-utilities.cpp
${GTEST_SRC})
diff --git a/libgnucash/engine/gnc-datetime.cpp b/libgnucash/engine/gnc-datetime.cpp
index a9c4f6b..c73fc0a 100644
--- a/libgnucash/engine/gnc-datetime.cpp
+++ b/libgnucash/engine/gnc-datetime.cpp
@@ -32,14 +32,19 @@ extern "C"
#include <boost/date_time/local_time/local_time.hpp>
#include <boost/regex.hpp>
#include <libintl.h>
+#include <locale.h>
#include <map>
#include <memory>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
+#include <gnc-locale-utils.hpp>
#include "gnc-timezone.hpp"
#include "gnc-datetime.hpp"
+#include "qoflog.h"
+
+static const char* log_module = "gnc.engine";
#define N_(string) string //So that xgettext will find it
@@ -440,8 +445,7 @@ GncDateTimeImpl::format(const char* format) const
//The stream destructor frees the facet, so it must be heap-allocated.
auto output_facet(new Facet(normalize_format(format).c_str()));
// FIXME Rather than imbueing a locale below we probably should set std::locale::global appropriately somewhere.
- // At that point the use of cachedLocale mechanism should be removed.
- ss.imbue(std::locale(cachedLocale, output_facet));
+ ss.imbue(std::locale(gnc_get_locale(), output_facet));
ss << m_time;
return ss.str();
}
@@ -454,7 +458,7 @@ GncDateTimeImpl::format_zulu(const char* format) const
//The stream destructor frees the facet, so it must be heap-allocated.
auto output_facet(new Facet(normalize_format(format).c_str()));
// FIXME Rather than imbueing a locale below we probably should set std::locale::global appropriately somewhere.
- ss.imbue(std::locale(std::locale(""), output_facet));
+ ss.imbue(std::locale(gnc_get_locale(), output_facet));
ss << m_time.utc_time();
return ss.str();
}
@@ -530,7 +534,7 @@ GncDateImpl::format(const char* format) const
//The stream destructor frees the facet, so it must be heap-allocated.
auto output_facet(new Facet(normalize_format(format).c_str()));
// FIXME Rather than imbueing a locale below we probably should set std::locale::global appropriately somewhere.
- ss.imbue(std::locale(std::locale(""), output_facet));
+ ss.imbue(std::locale(gnc_get_locale(), output_facet));
ss << m_greg;
return ss.str();
}
diff --git a/libgnucash/engine/test/CMakeLists.txt b/libgnucash/engine/test/CMakeLists.txt
index 5acda90..1a27ea7 100644
--- a/libgnucash/engine/test/CMakeLists.txt
+++ b/libgnucash/engine/test/CMakeLists.txt
@@ -104,6 +104,7 @@ set(gtest_qof_LIBS
set(gtest_engine_INCLUDES
${MODULEPATH}
+ ${CMAKE_SOURCE_DIR}/libgnucash/core-utils
${CMAKE_BINARY_DIR}/common # for config.h
${CMAKE_SOURCE_DIR}/common # for platform.h
${GLIB2_INCLUDE_DIRS}
@@ -156,6 +157,7 @@ set(test_gnc_rational_SOURCES
${MODULEPATH}/gnc-timezone.cpp
${MODULEPATH}/gnc-date.cpp
${MODULEPATH}/qoflog.cpp
+ ${CMAKE_SOURCE_DIR}/libgnucash/core-utils/gnc-locale-utils.cpp
${gtest_engine_win32_SOURCES}
gtest-gnc-rational.cpp
${GTEST_SRC})
@@ -171,6 +173,7 @@ set(test_gnc_numeric_SOURCES
${MODULEPATH}/gnc-timezone.cpp
${MODULEPATH}/gnc-date.cpp
${MODULEPATH}/qoflog.cpp
+ ${CMAKE_SOURCE_DIR}/libgnucash/core-utils/gnc-locale-utils.cpp
${gtest_engine_win32_SOURCES}
gtest-gnc-numeric.cpp
${GTEST_SRC})
@@ -189,6 +192,7 @@ set(test_gnc_datetime_SOURCES
${MODULEPATH}/gnc-timezone.cpp
${MODULEPATH}/gnc-date.cpp
${MODULEPATH}/qoflog.cpp
+ ${CMAKE_SOURCE_DIR}/libgnucash/core-utils/gnc-locale-utils.cpp
${gtest_engine_win32_SOURCES}
gtest-gnc-datetime.cpp
${GTEST_SRC})
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 8e327ea..e8c56ac 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -613,6 +613,7 @@ libgnucash/core-utils/gnc-glib-utils.c
libgnucash/core-utils/gnc-guile-utils.c
libgnucash/core-utils/gnc-jalali.c
libgnucash/core-utils/gnc-locale-utils.c
+libgnucash/core-utils/gnc-locale-utils.cpp
libgnucash/core-utils/gnc-path.c
libgnucash/core-utils/gnc-prefs.c
libgnucash/doc/doxygen_main_page.c
commit cee97be8d444441256f3b26db2c8061baa767894
Author: John Ralls <jralls at ceridwen.us>
Date: Sat Jan 5 14:53:25 2019 -0800
Add GncDateTime::timestamp().
To provide a C++ implementation of gnc_date_timestamp and to avoid
using the expensive and localized GncDateTime::format().
diff --git a/libgnucash/engine/gnc-date.cpp b/libgnucash/engine/gnc-date.cpp
index cacc35f..1e3236d 100644
--- a/libgnucash/engine/gnc-date.cpp
+++ b/libgnucash/engine/gnc-date.cpp
@@ -1075,7 +1075,7 @@ qof_strftime(gchar *buf, gsize max, const gchar *format, const struct tm *tm)
gchar *
gnc_date_timestamp (void)
{
- return gnc_print_time64(gnc_time(nullptr), "%Y%m%d%H%M%S");
+ return g_strdup(GncDateTime::timestamp().c_str());
}
/********************************************************************\
diff --git a/libgnucash/engine/gnc-datetime.cpp b/libgnucash/engine/gnc-datetime.cpp
index 70d9275..a9c4f6b 100644
--- a/libgnucash/engine/gnc-datetime.cpp
+++ b/libgnucash/engine/gnc-datetime.cpp
@@ -236,6 +236,7 @@ public:
std::string format(const char* format) const;
std::string format_zulu(const char* format) const;
std::string format_iso8601() const;
+ static std::string timestamp();
private:
LDT m_time;
static const TD time_of_day[3];
@@ -466,6 +467,14 @@ GncDateTimeImpl::format_iso8601() const
return str.substr(0, 19);
}
+std::string
+GncDateTimeImpl::timestamp()
+{
+ GncDateTimeImpl gdt;
+ auto str = boost::posix_time::to_iso_string(gdt.m_time.local_time());
+ return str.substr(0, 8) + str.substr(9, 15);
+}
+
/* Member function definitions for GncDateImpl.
*/
GncDateImpl::GncDateImpl(const std::string str, const std::string fmt) :
@@ -600,6 +609,12 @@ GncDateTime::format_iso8601() const
return m_impl->format_iso8601();
}
+std::string
+GncDateTime::timestamp()
+{
+ return GncDateTimeImpl::timestamp();
+}
+
/* GncDate */
GncDate::GncDate() : m_impl{new GncDateImpl} {}
GncDate::GncDate(int year, int month, int day) :
diff --git a/libgnucash/engine/gnc-datetime.hpp b/libgnucash/engine/gnc-datetime.hpp
index 8f714f5..58d1f32 100644
--- a/libgnucash/engine/gnc-datetime.hpp
+++ b/libgnucash/engine/gnc-datetime.hpp
@@ -152,7 +152,11 @@ public:
* @return a std::string in the format YYYY-MM-DD HH:MM:SS.
*/
std::string format_iso8601() const;
-
+/** Get an undelimited string representing the current date and time.
+ * @return a std::string in the format YYYYMMDDHHMMSS.
+ */
+ static std::string timestamp();
+
private:
std::unique_ptr<GncDateTimeImpl> m_impl;
};
Summary of changes:
gnucash/gnome/assistant-loan.cpp | 3 +-
.../csv-imp/assistant-csv-trans-import.cpp | 3 +-
libgnucash/core-utils/CMakeLists.txt | 2 +
libgnucash/core-utils/gnc-filepath-utils.cpp | 4 +-
libgnucash/core-utils/gnc-locale-utils.cpp | 78 ++++++++++++++++++++++
.../escape.h => core-utils/gnc-locale-utils.hpp} | 36 +++++-----
libgnucash/core-utils/test/CMakeLists.txt | 1 +
libgnucash/engine/gnc-date.cpp | 2 +-
libgnucash/engine/gnc-datetime.cpp | 27 ++++++--
libgnucash/engine/gnc-datetime.hpp | 6 +-
libgnucash/engine/test/CMakeLists.txt | 4 ++
po/POTFILES.in | 1 +
12 files changed, 136 insertions(+), 31 deletions(-)
create mode 100644 libgnucash/core-utils/gnc-locale-utils.cpp
copy libgnucash/{backend/sql/escape.h => core-utils/gnc-locale-utils.hpp} (67%)
More information about the gnucash-changes
mailing list