gnucash maint: Multiple changes pushed

John Ralls jralls at code.gnucash.org
Mon May 28 12:00:07 EDT 2018


Updated	 via  https://github.com/Gnucash/gnucash/commit/74cbde2d (commit)
	 via  https://github.com/Gnucash/gnucash/commit/174752e2 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/8b1b25ae (commit)
	from  https://github.com/Gnucash/gnucash/commit/aa086893 (commit)



commit 74cbde2d4f8822c330e0eb75777d3e6c1758a58b
Author: John Ralls <jralls at ceridwen.us>
Date:   Mon May 28 08:56:01 2018 -0700

    normalize date formats the C++ way.

diff --git a/libgnucash/engine/gnc-date.cpp b/libgnucash/engine/gnc-date.cpp
index d82a2ae..edd6eac 100644
--- a/libgnucash/engine/gnc-date.cpp
+++ b/libgnucash/engine/gnc-date.cpp
@@ -733,24 +733,18 @@ floordiv(int a, int b)
  *   The 'O' and 'E' format modifiers are for localized input/output
  *   characters. Remove them as we are always using Arabic numbers.
  */
-static char *
-normalize_format (const char *format)
-{
-    gint counter = 0, n_counter = 0;
-    gchar *normalized;
-
-    normalized = g_strdup(format);
-    while (format[counter] != '\0')
-    {
-        normalized[n_counter] = format[counter];
-        if ((format[counter] == '%') && \
-            (format[counter+1] == 'E' || format[counter+1] == 'O'))
-            counter++;  // skip format modifier
-
-        counter++;
-        n_counter++;
-    }
-    normalized[n_counter] = '\0';
+static inline std::string
+normalize_format (const std::string& format)
+{
+    bool is_pct = false;
+    std::string normalized;
+    std::remove_copy_if(
+        format.begin(), format.end(), back_inserter(normalized),
+        [&is_pct](char e){
+            bool r = (is_pct && (e == 'E' || e == 'O' || e == '-'));
+            is_pct = e == '%';
+            return r;
+        });
     return normalized;
 }
 
@@ -846,12 +840,9 @@ qof_scan_date_internal (const char *buff, int *day, int *month, int *year,
         if (buff[0] != '\0')
         {
             struct tm thetime;
-            gchar *normalized_format = normalize_format(GNC_D_FMT);
-
             /* Parse time string. */
             memset(&thetime, -1, sizeof(struct tm));
-            strptime (buff, normalized_format, &thetime);
-            g_free (normalized_format);
+            strptime (buff, normalize_format(GNC_D_FMT).c_str(), &thetime);
 
             if (third_field)
             {
@@ -1045,13 +1036,12 @@ char dateSeparator (void)
             struct tm tm;
             time64 secs;
             gchar *s;
-            gchar *normalized_fmt;
 
             secs = gnc_time (NULL);
             gnc_localtime_r(&secs, &tm);
-            normalized_fmt = normalize_format(qof_date_format_get_string(dateFormat));
-            qof_strftime(string, sizeof(string), normalized_fmt, &tm);
-            g_free(normalized_fmt);
+            auto normalized_fmt =
+                normalize_format(qof_date_format_get_string(dateFormat));
+            qof_strftime(string, sizeof(string), normalized_fmt.c_str(), &tm);
 
             for (s = string; *s != '\0'; s++)
                 if (!isdigit(*s))
diff --git a/libgnucash/engine/gnc-datetime.cpp b/libgnucash/engine/gnc-datetime.cpp
index e1f9f4f..f8b52dd 100644
--- a/libgnucash/engine/gnc-datetime.cpp
+++ b/libgnucash/engine/gnc-datetime.cpp
@@ -293,30 +293,6 @@ tz_from_string(std::string str)
     return TZ_Ptr(new PTZ(tzstr));
 }
 
-/* The 'O', 'E', and '-' format modifiers are not supported by
- * boost's output facets. Remove them.
- */
-static char *
-normalize_format (const char *format)
-{
-    int counter = 0, n_counter = 0;
-    char *normalized;
-
-    normalized = strdup(format);
-    while (format[counter] != '\0')
-    {
-        normalized[n_counter] = format[counter];
-        if ((format[counter] == '%') && \
-            (format[counter+1] == '-' || format[counter+1] == 'E' || format[counter+1] == 'O'))
-            counter++;  // skip format modifier
-
-        counter++;
-        n_counter++;
-    }
-    normalized[n_counter] = '\0';
-    return normalized;
-}
-
 GncDateTimeImpl::GncDateTimeImpl(std::string str) :
     m_time(unix_epoch, utc_zone)
 {
@@ -394,16 +370,32 @@ GncDateTimeImpl::date() const
     return std::unique_ptr<GncDateImpl>(new GncDateImpl(m_time.local_time().date()));
 }
 
+/* The 'O', 'E', and '-' format modifiers are not supported by
+ * boost's output facets. Remove them.
+ */
+static inline std::string
+normalize_format (const std::string& format)
+{
+    bool is_pct = false;
+    std::string normalized;
+    std::remove_copy_if(
+        format.begin(), format.end(), back_inserter(normalized),
+        [&is_pct](char e){
+            bool r = (is_pct && (e == 'E' || e == 'O' || e == '-'));
+            is_pct = e == '%';
+            return r;
+        });
+    return normalized;
+}
+
 std::string
 GncDateTimeImpl::format(const char* format) const
 {
     using Facet = boost::local_time::local_time_facet;
     std::stringstream ss;
-    char *normalized_format = normalize_format(format);
     //The stream destructor frees the facet, so it must be heap-allocated.
-    auto output_facet(new Facet(normalized_format));
+    auto output_facet(new Facet(normalize_format(format).c_str()));
     ss.imbue(std::locale(std::locale(), output_facet));
-    free(normalized_format);
     ss << m_time;
     return ss.str();
 }
@@ -413,11 +405,9 @@ GncDateTimeImpl::format_zulu(const char* format) const
 {
     using Facet = boost::posix_time::time_facet;
     std::stringstream ss;
-    char *normalized_format = normalize_format(format);
     //The stream destructor frees the facet, so it must be heap-allocated.
-    auto output_facet(new Facet(normalized_format));
+    auto output_facet(new Facet(normalize_format(format).c_str()));
     ss.imbue(std::locale(std::locale(), output_facet));
-    free(normalized_format);
     ss << m_time.utc_time();
     return ss.str();
 }
@@ -474,11 +464,9 @@ GncDateImpl::format(const char* format) const
 {
     using Facet = boost::gregorian::date_facet;
     std::stringstream ss;
-    char *normalized_format = normalize_format(format);
     //The stream destructor frees the facet, so it must be heap-allocated.
-    auto output_facet(new Facet(normalized_format));
+    auto output_facet(new Facet(normalize_format(format).c_str()));
     ss.imbue(std::locale(std::locale(), output_facet));
-    free(normalized_format);
     ss << m_greg;
     return ss.str();
 }

commit 174752e28c83787eeb15f0ccfc77f60b7a3087f4
Merge: aa08689 8b1b25a
Author: John Ralls <jralls at ceridwen.us>
Date:   Sat May 26 18:10:02 2018 -0700

    Merge Bill Nottingham's 'bad-dates' into maint


commit 8b1b25aee52d3c844a4cbecba7c80b3cd5d8627b
Author: Bill Nottingham <notting at splat.cc>
Date:   Tue May 22 23:37:22 2018 -0400

    Modify date formatters to strip out certian specifiers.
    
    strptime/strftime supports various modifiers to their parameters.
    
     'E' and 'O': alternate locale-specific formats
     (used in default format for Persian, Oriya, Azerbaijani)
     '-': padding
     (used in default format for Czech)
    
    GnuCash passes dates as integer y/m/d without using locale-specific
    formats, so we need to strip out 'E' and 'O' from the format when
    scanning dates or determining separators in gnc-date.
    
    None of '-', 'E', or 'O' are supported by boost (and '-' causes
    errors), so strip them out from formatters in gnc-datetime as well.
    
    See https://bugzilla.gnome.org/show_bug.cgi?id=795247.

diff --git a/libgnucash/engine/gnc-date.cpp b/libgnucash/engine/gnc-date.cpp
index 881c090..d82a2ae 100644
--- a/libgnucash/engine/gnc-date.cpp
+++ b/libgnucash/engine/gnc-date.cpp
@@ -728,6 +728,32 @@ floordiv(int a, int b)
     }
 }
 
+/* Normalize the localized date format to avoid date scanning issues.
+ *
+ *   The 'O' and 'E' format modifiers are for localized input/output
+ *   characters. Remove them as we are always using Arabic numbers.
+ */
+static char *
+normalize_format (const char *format)
+{
+    gint counter = 0, n_counter = 0;
+    gchar *normalized;
+
+    normalized = g_strdup(format);
+    while (format[counter] != '\0')
+    {
+        normalized[n_counter] = format[counter];
+        if ((format[counter] == '%') && \
+            (format[counter+1] == 'E' || format[counter+1] == 'O'))
+            counter++;  // skip format modifier
+
+        counter++;
+        n_counter++;
+    }
+    normalized[n_counter] = '\0';
+    return normalized;
+}
+
 /* Convert a string into  day, month and year integers
 
     Convert a string into  day / month / year integers according to
@@ -820,30 +846,12 @@ qof_scan_date_internal (const char *buff, int *day, int *month, int *year,
         if (buff[0] != '\0')
         {
             struct tm thetime;
-            gchar *format = g_strdup (GNC_D_FMT);
-            gchar *stripped_format = g_strdup (GNC_D_FMT);
-            gint counter = 0, stripped_counter = 0;
-
-            /* strptime can't handle the - format modifier
-             * let's strip it out of the format before using it
-             */
-            while (format[counter] != '\0')
-            {
-                stripped_format[stripped_counter] = format[counter];
-                if ((format[counter] == '%') && (format[counter+1] == '-'))
-                    counter++;  // skip - format modifier
-
-                counter++;
-                stripped_counter++;
-            }
-            stripped_format[stripped_counter] = '\0';
-            g_free (format);
-
+            gchar *normalized_format = normalize_format(GNC_D_FMT);
 
             /* Parse time string. */
             memset(&thetime, -1, sizeof(struct tm));
-            strptime (buff, stripped_format, &thetime);
-            g_free (stripped_format);
+            strptime (buff, normalized_format, &thetime);
+            g_free (normalized_format);
 
             if (third_field)
             {
@@ -1037,10 +1045,13 @@ char dateSeparator (void)
             struct tm tm;
             time64 secs;
             gchar *s;
+            gchar *normalized_fmt;
 
             secs = gnc_time (NULL);
             gnc_localtime_r(&secs, &tm);
-            qof_strftime(string, sizeof(string), GNC_D_FMT, &tm);
+            normalized_fmt = normalize_format(qof_date_format_get_string(dateFormat));
+            qof_strftime(string, sizeof(string), normalized_fmt, &tm);
+            g_free(normalized_fmt);
 
             for (s = string; *s != '\0'; s++)
                 if (!isdigit(*s))
diff --git a/libgnucash/engine/gnc-datetime.cpp b/libgnucash/engine/gnc-datetime.cpp
index d0958de..344fe5c 100644
--- a/libgnucash/engine/gnc-datetime.cpp
+++ b/libgnucash/engine/gnc-datetime.cpp
@@ -289,6 +289,30 @@ tz_from_string(std::string str)
     return TZ_Ptr(new PTZ(tzstr));
 }
 
+/* The 'O', 'E', and '-' format modifiers are not supported by
+ * boost's output facets. Remove them.
+ */
+static char *
+normalize_format (const char *format)
+{
+    int counter = 0, n_counter = 0;
+    char *normalized;
+
+    normalized = strdup(format);
+    while (format[counter] != '\0')
+    {
+        normalized[n_counter] = format[counter];
+        if ((format[counter] == '%') && \
+            (format[counter+1] == '-' || format[counter+1] == 'E' || format[counter+1] == 'O'))
+            counter++;  // skip format modifier
+
+        counter++;
+        n_counter++;
+    }
+    normalized[n_counter] = '\0';
+    return normalized;
+}
+
 GncDateTimeImpl::GncDateTimeImpl(std::string str) :
     m_time(unix_epoch, utc_zone)
 {
@@ -371,9 +395,11 @@ GncDateTimeImpl::format(const char* format) const
 {
     using Facet = boost::local_time::local_time_facet;
     std::stringstream ss;
+    char *normalized_format = normalize_format(format);
     //The stream destructor frees the facet, so it must be heap-allocated.
-    auto output_facet(new Facet(format));
+    auto output_facet(new Facet(normalized_format));
     ss.imbue(std::locale(std::locale(), output_facet));
+    free(normalized_format);
     ss << m_time;
     return ss.str();
 }
@@ -383,9 +409,11 @@ GncDateTimeImpl::format_zulu(const char* format) const
 {
     using Facet = boost::posix_time::time_facet;
     std::stringstream ss;
+    char *normalized_format = normalize_format(format);
     //The stream destructor frees the facet, so it must be heap-allocated.
-    auto output_facet(new Facet(format));
+    auto output_facet(new Facet(normalized_format));
     ss.imbue(std::locale(std::locale(), output_facet));
+    free(normalized_format);
     ss << m_time.utc_time();
     return ss.str();
 }
@@ -442,9 +470,11 @@ GncDateImpl::format(const char* format) const
 {
     using Facet = boost::gregorian::date_facet;
     std::stringstream ss;
+    char *normalized_format = normalize_format(format);
     //The stream destructor frees the facet, so it must be heap-allocated.
-    auto output_facet(new Facet(format));
+    auto output_facet(new Facet(normalized_format));
     ss.imbue(std::locale(std::locale(), output_facet));
+    free(normalized_format);
     ss << m_greg;
     return ss.str();
 }



Summary of changes:
 libgnucash/engine/gnc-date.cpp     | 47 +++++++++++++++++++-------------------
 libgnucash/engine/gnc-datetime.cpp | 24 ++++++++++++++++---
 2 files changed, 45 insertions(+), 26 deletions(-)



More information about the gnucash-changes mailing list