gnucash master: Multiple changes pushed

Geert Janssens gjanssens at code.gnucash.org
Fri Apr 28 14:50:25 EDT 2017


Updated	 via  https://github.com/Gnucash/gnucash/commit/1a3595cb (commit)
	 via  https://github.com/Gnucash/gnucash/commit/7a037932 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/586b89c6 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/610f6309 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/209f9715 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/9b30bb2b (commit)
	 via  https://github.com/Gnucash/gnucash/commit/b7bcd792 (commit)
	 via  https://github.com/Gnucash/gnucash/commit/b5530bd4 (commit)
	from  https://github.com/Gnucash/gnucash/commit/39195597 (commit)



commit 1a3595cbeb6b6cb3b5771d0e303c0139949169aa
Author: Geert Janssens <geert at kobaltwit.be>
Date:   Fri Apr 28 16:42:54 2017 +0200

    Convert gnc_dmy2timespec{,_end,_neutral} to use the equivalent GncDateTime constructor
    
    This required a couple of tweaks to the tests because:
    - the invalid date returned for impossible conversions is different between the old implementation and the cpp edition
    - unhandled glib warnings caused the tests to abort

diff --git a/src/engine/test/test-date.cpp b/src/engine/test/test-date.cpp
index 6efc39b..3600e3e 100644
--- a/src/engine/test/test-date.cpp
+++ b/src/engine/test/test-date.cpp
@@ -99,8 +99,10 @@ check_conversion (const char * str, Timespec expected_ts)
             || (g_date_get_year(&d1) != year))
     {
         fprintf (stderr,
-                 "\nmis-converted \"%s\" to GDate\n",
-                 str);
+                 "\nmis-converted \"%s\" to GDate. "
+                 "Got d1(Y-M-D) = %i-%i-%i, d2(Y-M-D) = %i-%i-%i\n",
+                 str, year, month, day,
+                 g_date_get_year(&d2), g_date_get_month(&d2), g_date_get_day(&d2));
         failure ("misconverted timespec");
         return FALSE;
     }
diff --git a/src/engine/test/utest-gnc-pricedb.c b/src/engine/test/utest-gnc-pricedb.c
index 691e4bf..b8f5d85 100644
--- a/src/engine/test/utest-gnc-pricedb.c
+++ b/src/engine/test/utest-gnc-pricedb.c
@@ -968,6 +968,11 @@ gnc_pricedb_lookup_day(GNCPriceDB *db,// C: 4 in 2 SCM: 2 in 1 Local: 1:0:0
 static void
 test_gnc_pricedb_lookup_day (PriceDBFixture *fixture, gconstpointer pData)
 {
+    gchar *msg1 = "[gnc_dmy2timespec_internal()] Date computation error from Y-M-D 12-11-18: Year is out of valid range: 1400..10000";
+    gint loglevel = G_LOG_LEVEL_CRITICAL | G_LOG_FLAG_FATAL;
+    gchar *logdomain = "qof.engine";
+    TestErrorStruct check = {loglevel, logdomain, msg1, 0};
+    GLogFunc hdlr = g_log_set_default_handler ((GLogFunc)test_null_handler, &check);
     Timespec t = gnc_dmy2timespec(17, 11, 2012);
     GNCPrice *price = gnc_pricedb_lookup_day(fixture->pricedb,
                                              fixture->com->usd,
@@ -978,11 +983,13 @@ test_gnc_pricedb_lookup_day (PriceDBFixture *fixture, gconstpointer pData)
                                    fixture->com->usd,
                                    fixture->com->gbp, t);
     g_assert_cmpstr(GET_COM_NAME(price), ==, "GBP");
+    g_test_log_set_fatal_handler ((GTestLogFatalFunc)test_checked_handler, &check);
     t = gnc_dmy2timespec(18, 11, 12);
     price = gnc_pricedb_lookup_day(fixture->pricedb,
                                    fixture->com->usd,
                                    fixture->com->gbp, t);
     g_assert(price == NULL);
+    g_log_set_default_handler (hdlr, 0);
 }
 
 // Not Used
diff --git a/src/libqof/qof/gnc-date.cpp b/src/libqof/qof/gnc-date.cpp
index 066a34a..b078da8 100644
--- a/src/libqof/qof/gnc-date.cpp
+++ b/src/libqof/qof/gnc-date.cpp
@@ -1255,78 +1255,44 @@ gnc_timespec2dmy (Timespec t, int *day, int *month, int *year)
 #define THIRTY_TWO_YEARS 0x3c30fc00LL
 
 static Timespec
-gnc_dmy2timespec_internal (int day, int month, int year, gboolean start_of_day)
+gnc_dmy2timespec_internal (int day, int month, int year, DayPart day_part)
 {
-    Timespec result;
-    struct tm date;
-    long long secs = 0;
-
-    date.tm_year = year - 1900;
-    date.tm_mon = month - 1;
-    date.tm_mday = day;
-
-    if (start_of_day)
-        gnc_tm_set_day_start(&date);
-    else
-        gnc_tm_set_day_end(&date);
-
-    /* compute number of seconds */
-    secs = gnc_mktime (&date);
-
-    result.tv_sec = secs;
-    result.tv_nsec = 0;
-
-    return result;
+    try
+    {
+        auto date = GncDate(year, month, day);
+        return { static_cast<time64>(GncDateTime (date, day_part)), 0 };
+    }
+    catch(const std::logic_error& err)
+    {
+        PWARN("Date computation error from Y-M-D %d-%d-%d: %s",
+              year, month, day, err.what());
+        return {INT64_MAX, 0};
+    }
+    catch(const std::runtime_error& err)
+    {
+        PWARN("Date computation error from Y-M-D %d-%d-%d: %s",
+              year, month, day, err.what());
+        return {INT64_MAX, 0};
+    }
 }
 
 
 Timespec
 gnc_dmy2timespec (int day, int month, int year)
 {
-    return gnc_dmy2timespec_internal (day, month, year, TRUE);
+    return gnc_dmy2timespec_internal (day, month, year, DayPart::start);
 }
 
 Timespec
 gnc_dmy2timespec_end (int day, int month, int year)
 {
-    return gnc_dmy2timespec_internal (day, month, year, FALSE);
+    return gnc_dmy2timespec_internal (day, month, year, DayPart::end);
 }
 
 Timespec
 gnc_dmy2timespec_neutral (int day, int month, int year)
 {
-    struct tm date;
-    memset (&date, 0, sizeof(struct tm));
-    date.tm_year = year - 1900;
-    date.tm_mon = month - 1;
-    date.tm_mday = day;
-    date.tm_hour = 10;
-    date.tm_min = 59;
-    date.tm_sec = 0;
-
-    try
-    {
-        GncDateTime gncdt(date);
-        auto offset = gncdt.offset() / 3600;
-        if (offset < -11)
-            date.tm_hour = -offset;
-        if (offset > 13)
-            date.tm_hour = 23 - offset;
-
-        return {gnc_timegm(&date), 0};
-    }
-    catch(const std::logic_error& err)
-    {
-        PWARN("Date computation error from Y-M-D %d-%d-%d: %s",
-              year, month, day, err.what());
-        return {INT64_MAX, 0};
-    }
-    catch(const std::runtime_error& err)
-    {
-        PWARN("Date computation error from Y-M-D %d-%d-%d: %s",
-              year, month, day, err.what());
-        return {INT64_MAX, 0};
-    }
+    return gnc_dmy2timespec_internal (day, month, year, DayPart::neutral);
 }
 /********************************************************************\
 \********************************************************************/
diff --git a/src/libqof/qof/test/test-gnc-date.c b/src/libqof/qof/test/test-gnc-date.c
index 3e00d8c..489bf9b 100644
--- a/src/libqof/qof/test/test-gnc-date.c
+++ b/src/libqof/qof/test/test-gnc-date.c
@@ -114,10 +114,10 @@ setup_begin(FixtureB *f, gconstpointer pData)
     f->test[1] = (TimeMap){1918, 3, 31, INT64_C(-1633305600)};
     f->test[2] = (TimeMap){1918, 4, 1, INT64_C(-1633219200)};
     f->test[3] = (TimeMap){2057, 11, 20, INT64_C(2773440000)};
-    f->test[4] = (TimeMap){1257, 07, 02, INT64_C(21695385600)}; /*invalid year*/
-    f->test[5] = (TimeMap){2017, 02, 29, INT64_C(1488326400)}; /*invalid day*/
-    f->test[6] = (TimeMap){2017, 02, 33, INT64_C(1488672000)}; /*invalid day*/
-    f->test[7] = (TimeMap){2017, 13, 29, INT64_C(1517184000)}; /*invalid month*/
+    f->test[4] = (TimeMap){1257, 07, 02, INT64_MAX}; /*invalid year*/
+    f->test[5] = (TimeMap){2017, 02, 29, INT64_MAX}; /*invalid day*/
+    f->test[6] = (TimeMap){2017, 02, 33, INT64_MAX}; /*invalid day*/
+    f->test[7] = (TimeMap){2017, 13, 29, INT64_MAX}; /*invalid month*/
     f->test[8] = (TimeMap){2017, 03, 16, INT64_C(1489622400)};
 }
 
@@ -142,10 +142,10 @@ setup_end(FixtureB *f, gconstpointer pData)
     f->test[1] = (TimeMap){1918, 3, 31, INT64_C(-1633219201)};
     f->test[2] = (TimeMap){1918, 4, 1, INT64_C(-1633132801)};
     f->test[3] = (TimeMap){2057, 11, 20, INT64_C(2773526399)};
-    f->test[4] = (TimeMap){1257, 07, 02, INT64_C(21695471999)};
-    f->test[5] = (TimeMap){2017, 02, 29, INT64_C(1488412799)};
-    f->test[6] = (TimeMap){2017, 02, 33, INT64_C(1488758399)};
-    f->test[7] = (TimeMap){2017, 13, 29, INT64_C(1517270399)};
+    f->test[4] = (TimeMap){1257, 07, 02, INT64_MAX};
+    f->test[5] = (TimeMap){2017, 02, 29, INT64_MAX};
+    f->test[6] = (TimeMap){2017, 02, 33, INT64_MAX};
+    f->test[7] = (TimeMap){2017, 13, 29, INT64_MAX};
     f->test[8] = (TimeMap){2017, 03, 16, INT64_C(1489708799)};
 }
 
@@ -1807,7 +1807,12 @@ gnc_dmy2timespec (int day, int month, int year)// C: 8 in 5  Local: 1:0:0
 static void
 test_gnc_dmy2timespec (FixtureB *f, gconstpointer pData)
 {
-
+    gchar *msg1 = "[qof_dmy2timespec()] Date computation error from Y-M-D 1257-7-2: Time value is outside the supported year range.";
+    gint loglevel = G_LOG_LEVEL_CRITICAL | G_LOG_FLAG_FATAL;
+    gchar *logdomain = "qof.engine";
+    TestErrorStruct check = {loglevel, logdomain, msg1, 0};
+    GLogFunc hdlr = g_log_set_default_handler ((GLogFunc)test_null_handler, &check);
+    g_test_log_set_fatal_handler ((GTestLogFatalFunc)test_checked_handler, &check);
     for (int i = 0; i < sizeof(f->test)/sizeof(TimeMap); ++i)
     {
 #ifdef HAVE_STRUCT_TM_GMTOFF
@@ -1820,8 +1825,14 @@ test_gnc_dmy2timespec (FixtureB *f, gconstpointer pData)
         Timespec r_t = gnc_dmy2timespec (f->test[i].day, f->test[i].mon,
                                          f->test[i].yr);
         int offset = gnc_mktime(&tm) - gnc_timegm(&tm);
-        g_assert_cmpint (r_t.tv_sec, ==, f->test[i].secs + offset);
+        if (f->test[i].secs == INT64_MAX)
+            /* We use INT64_MAX as invalid timespec.secs.
+             * As we can't *add* to the max, we can ignore the tz offset in this case. */
+            g_assert_cmpint (r_t.tv_sec, ==, INT64_MAX);
+        else
+            g_assert_cmpint (r_t.tv_sec, ==, f->test[i].secs + offset);
     }
+    g_log_set_default_handler (hdlr, 0);
 }
 /* gnc_dmy2timespec_end
 Timespec
@@ -1830,6 +1841,12 @@ gnc_dmy2timespec_end (int day, int month, int year)// C: 1  Local: 0:0:0
 static void
 test_gnc_dmy2timespec_end (FixtureB *f, gconstpointer pData)
 {
+    gchar *msg1 = "[qof_dmy2timespec_end()] Date computation error from Y-M-D 1257-7-2: Time value is outside the supported year range.";
+    gint loglevel = G_LOG_LEVEL_CRITICAL | G_LOG_FLAG_FATAL;
+    gchar *logdomain = "qof.engine";
+    TestErrorStruct check = {loglevel, logdomain, msg1, 0};
+    GLogFunc hdlr = g_log_set_default_handler ((GLogFunc)test_null_handler, &check);
+    g_test_log_set_fatal_handler ((GTestLogFatalFunc)test_checked_handler, &check);
     for (int i = 0; i < sizeof(f->test)/sizeof(TimeMap); ++i)
     {
 #ifdef HAVE_STRUCT_TM_GMTOFF
@@ -1842,8 +1859,14 @@ test_gnc_dmy2timespec_end (FixtureB *f, gconstpointer pData)
         Timespec r_t = gnc_dmy2timespec_end (f->test[i].day, f->test[i].mon,
                                              f->test[i].yr);
         int offset = gnc_mktime(&tm) - gnc_timegm(&tm);
-        g_assert_cmpint (r_t.tv_sec, ==, f->test[i].secs + offset);
+        if (f->test[i].secs == INT64_MAX)
+            /* We use INT64_MAX as invalid timespec.secs.
+             * As we can't *add* to the max, we can ignore the tz offset in this case. */
+            g_assert_cmpint (r_t.tv_sec, ==, INT64_MAX);
+        else
+            g_assert_cmpint (r_t.tv_sec, ==, f->test[i].secs + offset);
     }
+    g_log_set_default_handler (hdlr, 0);
 }
 
 static GDateTime*

commit 7a037932ae3a5a6aa3304344aa5138715168150d
Author: Geert Janssens <geert at kobaltwit.be>
Date:   Fri Apr 28 16:38:30 2017 +0200

    Align day end time as used in the GncDateTime constructor and gnc_dmy2timespec_end
    
    The former was using 23:59:00 while existing code was using 23:59:59. To avoid
    disruptions, stick with the latter in our cpp code as well.

diff --git a/src/libqof/qof/gnc-datetime.cpp b/src/libqof/qof/gnc-datetime.cpp
index a83fc04..6191cf7 100644
--- a/src/libqof/qof/gnc-datetime.cpp
+++ b/src/libqof/qof/gnc-datetime.cpp
@@ -223,7 +223,7 @@ GncDateTimeImpl::GncDateTimeImpl(const GncDateImpl& date, DayPart part) :
     using TD = boost::posix_time::time_duration;
     static const TD start(0, 0, 0);
     static const TD neutral(10, 59, 0);
-    static const TD end(23,59, 0);
+    static const TD end(23,59, 59);
     TD time_of_day;
     switch (part)
     {
diff --git a/src/libqof/qof/test/gtest-gnc-datetime.cpp b/src/libqof/qof/test/gtest-gnc-datetime.cpp
index 5f7c676..0730bd3 100644
--- a/src/libqof/qof/test/gtest-gnc-datetime.cpp
+++ b/src/libqof/qof/test/gtest-gnc-datetime.cpp
@@ -236,7 +236,7 @@ TEST(gnc_datetime_constructors, test_gncdate_end_constructor)
     const ymd aymd = { 2046, 11, 06 };
     GncDateTime atime(GncDate(aymd.year, aymd.month, aymd.day), DayPart::end);
     //Skipping timezone information as this can't be controlled.
-    EXPECT_EQ(atime.format("%d-%m-%Y %H:%M:%S"), "06-11-2046 23:59:00");
+    EXPECT_EQ(atime.format("%d-%m-%Y %H:%M:%S"), "06-11-2046 23:59:59");
 }
 
 TEST(gnc_datetime_constructors, test_gncdate_neutral_constructor)

commit 586b89c6ca7f647b54da4e26f97f060c80b084ec
Author: Geert Janssens <geert at kobaltwit.be>
Date:   Fri Apr 28 14:17:33 2017 +0200

    Fix John's remarks

diff --git a/src/import-export/csv-imp/gnc-tx-import.hpp b/src/import-export/csv-imp/gnc-tx-import.hpp
index c9eb8ca..fbded6e 100644
--- a/src/import-export/csv-imp/gnc-tx-import.hpp
+++ b/src/import-export/csv-imp/gnc-tx-import.hpp
@@ -68,16 +68,23 @@ extern const gchar* currency_format_user[];
 extern const int num_date_formats;
 extern const gchar* date_format_user[];
 
-/** Tuple to hold
+/** An enum describing the columns found in a parse_line_t. Currently these are:
  *  - a tokenized line of input
  *  - an optional error string
  *  - a struct to hold user selected properties for a transaction
- *  - a struct to hold user selected properties for one or two splits in the above transaction */
-#define PL_INPUT    0
-#define PL_ERROR    1
-#define PL_PRETRANS 2
-#define PL_PRESPLIT 3
-#define PL_SKIP     4
+ *  - a struct to hold user selected properties for one or two splits in the above transaction
+ *  - a boolean to mark the line as skipped by error and/or user or not */
+enum parse_line_cols {
+    PL_INPUT,
+    PL_ERROR,
+    PL_PRETRANS,
+    PL_PRESPLIT,
+    PL_SKIP
+};
+
+/** Tuple to hold all internal state for one parsed line. The contents of each
+ * colummn is described by the parse_line_cols enum. This enum should be used
+ * with std::get to access the columns. */
 using parse_line_t = std::tuple<StrVec,
                                 std::string,
                                 std::shared_ptr<GncPreTrans>,
diff --git a/src/libqof/qof/gnc-datetime.hpp b/src/libqof/qof/gnc-datetime.hpp
index 11880e1..59fb059 100644
--- a/src/libqof/qof/gnc-datetime.hpp
+++ b/src/libqof/qof/gnc-datetime.hpp
@@ -153,23 +153,61 @@ private:
     std::unique_ptr<GncDateTimeImpl> m_impl;
 };
 
+/** GnuCash DateFormat class
+ *
+ * A helper class to represent a date format understood
+ * by the GncDate string/format constructor. Consumers
+ * of this header file are not supposed to create
+ * objects of this class themselves. Instead they
+ * can get a list of the understood formats from the
+ * GncDate::c_formats class variable and work with those.
+ */
+
 class GncDateFormat
 {
 public:
+    /** Construct a GncDateFormat with a given format and corresponding
+     * regular expression. This should only be used internally by the
+     * GncDate implementation. Consumers should never construct a GncDateFormat
+     * themselves!
+     */
     GncDateFormat (const char* fmt, const char* re) :
     m_fmt(fmt), m_re(re) {}
+    /** A string representing the format. */
     const std::string m_fmt;
 private:
+    /** Regular expression associated with the format string. This is to and
+     * only be used internally by the gnc-datetime code.
+     */
     const std::string m_re;
 
     friend class GncDateImpl;
 };
 
+/** GnuCash Date class
+ *
+ * The represented date is limited to the period
+ * between 1400 and 9999 CE.
+ */
 
 class GncDate
 {
     public:
-        /** A vector with all the date formats supported by the string constructor
+        /** A vector with all the date formats supported by the string constructor.
+         * The currently supported formats are:
+         * "y-m-d" (including yyyymmdd)
+         * "d-m-y" (including ddmmyyyy)
+         * "m-d-y" (including mmddyyyy)
+         * "d-m"   (including ddmm)
+         * "m-d"   (including mmdd)
+         *
+         * Notes:
+         * - while the format names are using a "-" as separator, the
+         * regexes will accept any of "-/.' " and will also work for dates
+         * without separators.
+         * - the format strings are marked for translation so it is possible
+         * to use a localized version of a format string using gettext. Example:
+         * gettext(GncDate::c_formats[0])
          */
         static const std::vector<GncDateFormat> c_formats;
         /** Construct a GncDate representing the current day.

commit 610f6309a378b03d18e33315f29efaf3dd966ddd
Author: Geert Janssens <geert at kobaltwit.be>
Date:   Fri Apr 28 18:39:31 2017 +0200

    Fix double free abort in gtest-gnc-datetime.cpp
    
    This double free happened after the introduction of a class variable (static member variable
    to GndDate and the test compiling in gnc-datetime.cpp *and* at the same time linking to
    gnc-qof. This apparently threw off internal memory management. Removing either of linking to
    gnc-qof or compiling in the source file solved it.
    Credits go to John Ralls for debugging this.

diff --git a/src/libqof/qof/test/CMakeLists.txt b/src/libqof/qof/test/CMakeLists.txt
index 0b1cdf7..0749157 100644
--- a/src/libqof/qof/test/CMakeLists.txt
+++ b/src/libqof/qof/test/CMakeLists.txt
@@ -129,8 +129,11 @@ IF (NOT WIN32)
 
   SET(test_gnc_datetime_SOURCES
     ${MODULEPATH}/gnc-datetime.cpp
+    ${MODULEPATH}/gnc-timezone.cpp
+    ${MODULEPATH}/gnc-date.cpp
+    ${MODULEPATH}/qoflog.cpp
     gtest-gnc-datetime.cpp
     ${GTEST_SRC})
   GNC_ADD_TEST(test-gnc-datetime "${test_gnc_datetime_SOURCES}"
-    gtest_qof_INCLUDES gtest_old_qof_LIBS)
+    gtest_qof_INCLUDES gtest_qof_LIBS)
 ENDIF()
diff --git a/src/libqof/qof/test/Makefile.am b/src/libqof/qof/test/Makefile.am
index 53f3cec..1f43940 100644
--- a/src/libqof/qof/test/Makefile.am
+++ b/src/libqof/qof/test/Makefile.am
@@ -212,6 +212,8 @@ check_PROGRAMS += test-gnc-timezone
 test_gnc_datetime_SOURCES = \
         $(top_srcdir)/$(MODULEPATH)/gnc-datetime.cpp \
         $(top_srcdir)/$(MODULEPATH)/gnc-timezone.cpp \
+        $(top_srcdir)/$(MODULEPATH)/gnc-date.cpp \
+        $(top_srcdir)/${MODULEPATH}/qoflog.cpp \
         gtest-gnc-datetime.cpp
 test_gnc_datetime_CPPFLAGS =\
         -I$(GTEST_HEADERS) \
@@ -221,10 +223,9 @@ test_gnc_datetime_CPPFLAGS =\
         $(BOOST_CPPFLAGS)
 
 test_gnc_datetime_LDADD = \
-        -lboost_date_time \
-        ${top_builddir}/${MODULEPATH}/libgnc-qof.la \
         $(GLIB_LIBS) \
-        $(GTEST_LIBS)
+        $(GTEST_LIBS) \
+        ${BOOST_LDFLAGS} -lboost_regex -lboost_date_time
 if !GOOGLE_TEST_LIBS
 nodist_test_gnc_datetime_SOURCES = \
         $(GTEST_SRC)/src/gtest_main.cc

commit 209f97158974d9120e311de5d9bb70a5a10efc49
Author: Geert Janssens <geert at kobaltwit.be>
Date:   Fri Apr 21 16:58:20 2017 +0200

    Add constructor to create GncDate from string and predefined date format
    
    Primary use case is for parsing dates from external sources (importers)

diff --git a/src/libqof/qof/gnc-datetime.cpp b/src/libqof/qof/gnc-datetime.cpp
index f367d45..a83fc04 100644
--- a/src/libqof/qof/gnc-datetime.cpp
+++ b/src/libqof/qof/gnc-datetime.cpp
@@ -29,13 +29,19 @@ extern "C"
 }
 #include <boost/date_time/gregorian/gregorian.hpp>
 #include <boost/date_time/posix_time/posix_time.hpp>
+#include <boost/regex.hpp>
+#include <libintl.h>
+#include <map>
 #include <memory>
 #include <iostream>
 #include <sstream>
 #include <string>
+#include <vector>
 #include "gnc-timezone.hpp"
 #include "gnc-datetime.hpp"
 
+#define N_(string) string //So that xgettext will find it
+
 using Date = boost::gregorian::date;
 using Month = boost::gregorian::greg_month;
 using PTime = boost::posix_time::ptime;
@@ -58,6 +64,77 @@ static constexpr auto ticks_per_second = INT64_C(1000000);
 static constexpr auto ticks_per_second = INT64_C(1000000000);
 #endif
 
+/* Vector of date formats understood by gnucash and corresponding regex
+ * to parse each from an external source
+ * Note: while the format names are using a "-" as separator, the
+ * regexes will accept any of "-/.' " and will also work for dates
+ * without separators.
+ */
+const std::vector<GncDateFormat> GncDate::c_formats ({
+    GncDateFormat {
+        N_("y-m-d"),
+        "(?:"                                   // either y-m-d
+        "(?<YEAR>[0-9]+)[-/.' ]+"
+        "(?<MONTH>[0-9]+)[-/.' ]+"
+        "(?<DAY>[0-9]+)"
+        "|"                                     // or CCYYMMDD
+        "(?<YEAR>[0-9]{4})"
+        "(?<MONTH>[0-9]{2})"
+        "(?<DAY>[0-9]{2})"
+        ")"
+    },
+    GncDateFormat {
+        N_("d-m-y"),
+        "(?:"                                   // either d-m-y
+        "(?<DAY>[0-9]+)[-/.' ]+"
+        "(?<MONTH>[0-9]+)[-/.' ]+"
+        "(?<YEAR>[0-9]+)"
+        "|"                                     // or DDMMCCYY
+        "(?<DAY>[0-9]{2})"
+        "(?<MONTH>[0-9]{2})"
+        "(?<YEAR>[0-9]{4})"
+        ")"
+    },
+    GncDateFormat {
+        N_("m-d-y"),
+        "(?:"                                   // either m-d-y
+        "(?<MONTH>[0-9]+)[-/.' ]+"
+        "(?<DAY>[0-9]+)[-/.' ]+"
+        "(?<YEAR>[0-9]+)"
+        "|"                                     // or MMDDCCYY
+        "(?<MONTH>[0-9]{2})"
+        "(?<DAY>[0-9]{2})"
+        "(?<YEAR>[0-9]{4})"
+        ")"
+    },
+    // Note year is still checked for in the regexes below
+    // This is to be able to raise an error if one is found for a yearless date format
+    GncDateFormat {
+        (N_("d-m")),
+        "(?:"                                   // either d-m(-y)
+        "(?<DAY>[0-9]+)[-/.' ]+"
+        "(?<MONTH>[0-9]+)(?:[-/.' ]+"
+        "(?<YEAR>[0-9]+))?"
+        "|"                                     // or DDMM(CCYY)
+        "(?<DAY>[0-9]{2})"
+        "(?<MONTH>[0-9]{2})"
+        "(?<YEAR>[0-9]+)?"
+        ")"
+    },
+    GncDateFormat {
+        (N_("m-d")),
+        "(?:"                                   // either m-d(-y)
+        "(?<MONTH>[0-9]+)[-/.' ]+"
+        "(?<DAY>[0-9]+)(?:[-/.' ]+"
+        "(?<YEAR>[0-9]+))?"
+        "|"                                     // or MMDD(CCYY)
+        "(?<MONTH>[0-9]{2})"
+        "(?<DAY>[0-9]{2})"
+        "(?<YEAR>[0-9]+)?"
+        ")"
+    }
+});
+
 /** Private implementation of GncDateTime. See the documentation for that class.
  */
 static LDT
@@ -126,6 +203,7 @@ public:
     GncDateImpl(const int year, const int month, const int day) :
     m_greg(year, static_cast<Month>(month), day) {}
     GncDateImpl(Date d) : m_greg(d) {}
+    GncDateImpl(const std::string str, const std::string fmt);
 
     void today() { m_greg = boost::gregorian::day_clock::local_day(); }
     ymd year_month_day() const;
@@ -290,8 +368,46 @@ GncDateTimeImpl::format_zulu(const char* format) const
     return ss.str();
 }
 
-/* Member function definitions for GncDateTimeImpl.
+/* Member function definitions for GncDateImpl.
  */
+GncDateImpl::GncDateImpl(const std::string str, const std::string fmt) :
+    m_greg(boost::gregorian::day_clock::local_day()) /* Temporarily initialized to today, will be used and adjusted in the code below */
+{
+    auto iter = std::find_if(GncDate::c_formats.cbegin(), GncDate::c_formats.cend(),
+                             [&fmt](const GncDateFormat& v){ return (v.m_fmt == fmt); } );
+    if (iter == GncDate::c_formats.cend())
+        throw std::invalid_argument(N_("Unknown date format specifier passed as argument."));
+
+    boost::regex r(iter->m_re);
+    boost::smatch what;
+    if(!boost::regex_search(str, what, r))  // regex didn't find a match
+        throw std::invalid_argument (N_("Value can't be parsed into a date using the selected date format."));
+
+    // Bail out if a year was found with a yearless format specifier
+    auto fmt_has_year = (fmt.find('y') != std::string::npos);
+    if (!fmt_has_year && (what.length("YEAR") != 0))
+        throw std::invalid_argument (N_("Value appears to contain a year while the selected format forbids this."));
+
+    int year;
+    if (fmt_has_year)
+    {
+        /* The input dates have a year, so use that one */
+        year = std::stoi (what.str("YEAR"));
+
+        /* We assume two-digit years to be in the range 1969 - 2068. */
+        if (year < 69)
+                year += 2000;
+        else if (year < 100)
+                year += 1900;
+    }
+    else /* The input dates have no year, so use current year */
+        year = m_greg.year(); // Can use m_greg here as it was already initialized in the initializer list earlier
+
+    m_greg = Date(year,
+                  static_cast<Month>(std::stoi (what.str("MONTH"))),
+                  std::stoi (what.str("DAY")));
+}
+
 ymd
 GncDateImpl::year_month_day() const
 {
@@ -376,6 +492,8 @@ GncDateTime::format_zulu(const char* format) const
 GncDate::GncDate() : m_impl{new GncDateImpl} {}
 GncDate::GncDate(int year, int month, int day) :
 m_impl(new GncDateImpl(year, month, day)) {}
+GncDate::GncDate(const std::string str, const std::string fmt) :
+m_impl(new GncDateImpl(str, fmt)) {}
 GncDate::GncDate(std::unique_ptr<GncDateImpl> impl) :
 m_impl(std::move(impl)) {}
 GncDate::GncDate(GncDate&&) = default;
diff --git a/src/libqof/qof/gnc-datetime.hpp b/src/libqof/qof/gnc-datetime.hpp
index 74a3bad..11880e1 100644
--- a/src/libqof/qof/gnc-datetime.hpp
+++ b/src/libqof/qof/gnc-datetime.hpp
@@ -28,6 +28,7 @@
 #include <cstdint>
 #include <memory>
 #include <string>
+#include <vector>
 
 typedef struct
 {
@@ -152,11 +153,28 @@ private:
     std::unique_ptr<GncDateTimeImpl> m_impl;
 };
 
+class GncDateFormat
+{
+public:
+    GncDateFormat (const char* fmt, const char* re) :
+    m_fmt(fmt), m_re(re) {}
+    const std::string m_fmt;
+private:
+    const std::string m_re;
+
+    friend class GncDateImpl;
+};
+
+
 class GncDate
 {
-    public:/** Construct a GncDate representing the current day.
-        */
-        GncDate();;
+    public:
+        /** A vector with all the date formats supported by the string constructor
+         */
+        static const std::vector<GncDateFormat> c_formats;
+        /** Construct a GncDate representing the current day.
+         */
+        GncDate();
         /** Construct a GncDate representing the given year, month, and day in
          * the proleptic Gregorian calendar.
          *
@@ -171,6 +189,23 @@ class GncDate
          * of the constrained range.
          */
         GncDate(int year, int month, int day);
+        /** Construct a GncDate by parsing a string assumed to be in the format
+         * passed in.
+         *
+         * The currently recognized formats are d-m-y, m-d-y, y-m-d, m-d, d-m.
+         * Note while the format descriptions use "-" as separator any of
+         * "-" (hyphen), "/" (slash), "'" (single quote), " " (space) or
+         * "." will be accepted.
+         *
+         * @param str The string to be interpreted.
+         * @param fmt The expected date format of the string passed in.
+         * @exception std::invalid_argument if
+         * - the string couldn't be parsed using the provided format
+         * - any of the date components is outside of its limit
+         *   (like month being 13, or day being 31 in February)
+         * - fmt doesn't specify a year, yet a year was found in the string
+         */
+        GncDate(const std::string str, const std::string fmt);
         GncDate(std::unique_ptr<GncDateImpl> impl);
         GncDate(GncDate&&);
         ~GncDate();
diff --git a/src/libqof/qof/test/gtest-gnc-datetime.cpp b/src/libqof/qof/test/gtest-gnc-datetime.cpp
index 59b19e4..5f7c676 100644
--- a/src/libqof/qof/test/gtest-gnc-datetime.cpp
+++ b/src/libqof/qof/test/gtest-gnc-datetime.cpp
@@ -37,6 +37,152 @@ TEST(gnc_date_constructors, test_ymd_constructor)
     EXPECT_FALSE(date.isnull());
 }
 
+typedef struct
+{
+    const char* date_fmt;
+    const char* date_str;
+    int         exp_year;
+    int         exp_month;
+    int         exp_day;
+} parse_date_data;
+
+/* parse_date
+ * time64 parse_date (const char* date_str, int format)// C: 14 in 7 SCM: 9 in 2 Local: 1:0:0
+ */
+TEST(gnc_date_constructors, test_str_format_constructor)
+{
+    auto today = GncDate();
+    auto today_ymd = today.year_month_day();
+    auto curr_year = today_ymd.year;
+
+    parse_date_data test_dates[] =
+    {
+        // supported combinations  -/.'
+        { "y-m-d", "2013-08-01", 2013,  8,  1},
+        { "y-m-d",  "2013-8-01", 2013,  8,  1},
+        { "y-m-d",  "2013-08-1", 2013,  8,  1},
+        { "y-m-d",   "2013-8-1", 2013,  8,  1},
+        { "y-m-d",   "13-08-01", 2013,  8,  1},
+        { "y-m-d",    "13-8-01", 2013,  8,  1},
+        { "y-m-d",    "13-08-1", 2013,  8,  1},
+        { "y-m-d",     "13-8-1", 2013,  8,  1},
+        { "y-m-d", "2009/11/04", 2009, 11,  4},
+        { "y-m-d",  "1985.3.12", 1985,  3, 12},
+        { "y-m-d",      "3'6'8", 2003,  6,  8},
+        { "y-m-d",   "20130801", 2013,  8,  1},
+        { "d-m-y", "01-08-2013", 2013,  8,  1},
+        { "d-m-y",  "01-8-2013", 2013,  8,  1},
+        { "d-m-y",  "1-08-2013", 2013,  8,  1},
+        { "d-m-y",   "1-8-2013", 2013,  8,  1},
+        { "d-m-y",   "01-08-13", 2013,  8,  1},
+        { "d-m-y",    "01-8-13", 2013,  8,  1},
+        { "d-m-y",    "1-08-13", 2013,  8,  1},
+        { "d-m-y",     "1-8-13", 2013,  8,  1},
+        { "d-m-y", "04/11/2009", 2009, 11,  4},
+        { "d-m-y",  "12.3.1985", 1985,  3, 12},
+        { "d-m-y",      "8'6'3", 2003,  6,  8},
+        { "d-m-y",   "01082013", 2013,  8,  1},
+        { "m-d-y", "08-01-2013", 2013,  8,  1},
+        { "m-d-y",  "8-01-2013", 2013,  8,  1},
+        { "m-d-y",  "08-1-2013", 2013,  8,  1},
+        { "m-d-y",   "8-1-2013", 2013,  8,  1},
+        { "m-d-y",   "08-01-13", 2013,  8,  1},
+        { "m-d-y",    "8-01-13", 2013,  8,  1},
+        { "m-d-y",    "08-1-13", 2013,  8,  1},
+        { "m-d-y",     "8-1-13", 2013,  8,  1},
+        { "m-d-y", "11/04/2009", 2009, 11,  4},
+        { "m-d-y",  "3.12.1985", 1985,  3, 12},
+        { "m-d-y",      "6'8'3", 2003,  6,  8},
+        { "m-d-y",   "08012013", 2013,  8,  1},
+        {   "d-m",      "01-08",   curr_year,  8,  1},
+        {   "d-m",       "01-8",   curr_year,  8,  1},
+        {   "d-m",       "1-08",   curr_year,  8,  1},
+        {   "d-m",        "1-8",   curr_year,  8,  1},
+        {   "d-m",      "04/11",   curr_year, 11,  4},
+        {   "d-m",       "12.3",   curr_year,  3, 12},
+        {   "d-m",        "8'6",   curr_year,  6,  8},
+        {   "d-m",       "0108",   curr_year,  8,  1},
+        {   "m-d",      "08-01",   curr_year,  8,  1},
+        {   "m-d",       "8-01",   curr_year,  8,  1},
+        {   "m-d",       "08-1",   curr_year,  8,  1},
+        {   "m-d",        "8-1",   curr_year,  8,  1},
+        {   "m-d",      "11/04",   curr_year, 11,  4},
+        {   "m-d",       "3.12",   curr_year,  3, 12},
+        {   "m-d",        "6'8",   curr_year,  6,  8},
+        {   "m-d",       "0801",   curr_year,  8,  1},
+
+        // ambiguous date formats
+        // current parser doesn't know how to disambiguate
+        // and hence refuses to parse
+        // can possibly improved with a smarter parser
+        { "y-m-d",     "130801",          -1,     -1, -1},
+        { "d-m-y",     "010813",          -1,     -1, -1},
+        { "m-d-y",     "080113",          -1,     -1, -1},
+
+        // Combinations that don't make sense
+        // but can still be entered by a user
+        // Should ideally all result in refusal to parse...
+        { "y-m-d",      "08-01",          -1,     -1, -1},
+        { "y-m-d",       "0801",          -1,     -1, -1},
+        { "d-m-y",      "01-08",          -1,     -1, -1},
+        { "d-m-y",       "0108",          -1,     -1, -1},
+        { "m-d-y",      "08-01",          -1,     -1, -1},
+        { "m-d-y",       "0801",          -1,     -1, -1},
+        {   "d-m", "01-08-2013",          -1,     -1, -1},
+        {   "d-m",   "01-08-13",          -1,     -1, -1},
+        {   "d-m",   "08-08-08",          -1,     -1, -1},
+        {   "d-m",   "01082013",          -1,     -1, -1},
+        {   "d-m",     "010813",          -1,     -1, -1},
+        {   "d-m",   "20130108",          -1,     -1, -1},
+        {   "m-d", "08-01-2013",          -1,     -1, -1},
+        {   "m-d",   "08-01-13",          -1,     -1, -1},
+        {   "m-d", "2013-08-01",          -1,     -1, -1},
+        {   "m-d",   "09-08-01",          -1,     -1, -1},
+        {   "m-d",   "08012013",          -1,     -1, -1},
+        {   "m-d",     "080113",          -1,     -1, -1},
+        {   "m-d",   "20130801",          -1,     -1, -1},
+
+        // Unknown date format specifier should also trigger an exception
+        {   "y-d-m H:M:S",   "20130801",          -1,     -1, -1},
+
+        // Sentinel to mark the end of available tests
+        { "y-m-d",         NULL,           0,      0,  0},
+
+    };
+    int i = 0;
+
+    while (test_dates[i].date_str)
+    {
+        int got_year = 0, got_month = 0, got_day = 0;
+
+        try
+        {
+            auto test_date = GncDate (std::string(test_dates[i].date_str), test_dates[i].date_fmt);
+            auto test_ymd = test_date.year_month_day();
+            got_year = test_ymd.year;
+            got_month = test_ymd.month;
+            got_day = test_ymd.day;
+        }
+        catch (const std::invalid_argument& e)
+        {
+            got_year = got_month = got_day = -1;
+        }
+
+        EXPECT_TRUE ((got_year  == test_dates[i].exp_year) &&
+                     (got_month == test_dates[i].exp_month) &&
+                     (got_day   == test_dates[i].exp_day))
+            << "GncDate constructor failed for str " << test_dates[i].date_str
+            << " and fmt " << test_dates[i].date_fmt << ".\n"
+            << "Expected: year " << test_dates[i].exp_year
+                   << ", month " << test_dates[i].exp_month
+                     << ", day " << test_dates[i].exp_day << "\n"
+            << "Actual:   year " << got_year << ", month "
+                    << got_month << ", day " << got_day << "\n";
+
+        i++;
+    }
+}
+
 TEST(gnc_datetime_constructors, test_default_constructor)
 {
     GncDateTime atime;

commit 9b30bb2b629edbaaf7fa12854f3a7ba3ded84d36
Author: Geert Janssens <geert at kobaltwit.be>
Date:   Sat Apr 22 17:00:34 2017 +0200

    Various small fixups in csv importer
    
    - Use descriptive names instead of numbers in std::get<>
    - Remove unused parameters
    - Fix some doxigen comments

diff --git a/src/import-export/csv-imp/assistant-csv-trans-import.cpp b/src/import-export/csv-imp/assistant-csv-trans-import.cpp
index ce4ff79..05219da 100644
--- a/src/import-export/csv-imp/assistant-csv-trans-import.cpp
+++ b/src/import-export/csv-imp/assistant-csv-trans-import.cpp
@@ -793,7 +793,6 @@ CsvImpTransAssist::preview_settings_delete ()
 void
 CsvImpTransAssist::preview_settings_save ()
 {
-    auto title = _("Save the Import Settings.");
     auto new_name = tx_imp->settings_name();
 
     /* Check if the entry text matches an already existing preset */
@@ -889,7 +888,6 @@ void CsvImpTransAssist::preview_multi_split (bool multi)
  * separator checkbuttons or the custom separator entry) is
  * changed.
  * @param widget The widget that was changed
- * @param info The data that is being configured
  */
 void CsvImpTransAssist::preview_update_separators (GtkWidget* widget)
 {
@@ -952,8 +950,6 @@ void CsvImpTransAssist::preview_update_separators (GtkWidget* widget)
 
 /** Event handler for clicking one of the format type radio
  * buttons. This occurs if the format (Fixed-Width or CSV) is changed.
- * @param csv_button The "Separated" radio button
- * @param info The display of the data being imported
  */
 void CsvImpTransAssist::preview_update_file_format ()
 {
@@ -1007,7 +1003,6 @@ void CsvImpTransAssist::preview_update_account ()
 /** Event handler for a new encoding. This is called when the user
  * selects a new encoding; the data is reparsed and shown to the
  * user.
- * @param selector The widget the user uses to select a new encoding
  * @param encoding The encoding that the user selected
  */
 void
@@ -1080,10 +1075,7 @@ enum PreviewDataTableCols {
  * user selects a new column type, that column's text must be changed
  * to the selection, and any other columns containing that selection
  * must be changed to "None" because we don't allow duplicates.
- * @param renderer The renderer of the column the user changed
- * @param path There is only 1 row in info->ctreeview, so this is always 0.
- * @param new_text The text the user selected
- * @param info The display of the data being imported
+ * @param cbox The combo box the user just clicked to make a change
  */
 void CsvImpTransAssist::preview_update_col_type (GtkComboBox* cbox)
 {
@@ -1470,12 +1462,12 @@ void CsvImpTransAssist::preview_refresh_table ()
         GtkTreeIter iter;
         gtk_list_store_append (store, &iter);
         preview_row_fill_state_cells (store, &iter,
-                std::get<1>(parse_line), std::get<4>(parse_line));
+                std::get<PL_ERROR>(parse_line), std::get<PL_SKIP>(parse_line));
 
         /* Fill the data cells. */
-        for (auto cell_str_it = std::get<0>(parse_line).cbegin(); cell_str_it != std::get<0>(parse_line).cend(); cell_str_it++)
+        for (auto cell_str_it = std::get<PL_INPUT>(parse_line).cbegin(); cell_str_it != std::get<PL_INPUT>(parse_line).cend(); cell_str_it++)
         {
-            uint32_t pos = PREV_N_FIXED_COLS + cell_str_it - std::get<0>(parse_line).cbegin();
+            uint32_t pos = PREV_N_FIXED_COLS + cell_str_it - std::get<PL_INPUT>(parse_line).cbegin();
             gtk_list_store_set (store, &iter, pos, cell_str_it->c_str(), -1);
         }
     }
diff --git a/src/import-export/csv-imp/gnc-csv-trans-settings.cpp b/src/import-export/csv-imp/gnc-csv-trans-settings.cpp
index 82b436e..f3456f0 100644
--- a/src/import-export/csv-imp/gnc-csv-trans-settings.cpp
+++ b/src/import-export/csv-imp/gnc-csv-trans-settings.cpp
@@ -245,7 +245,7 @@ CsvTransSettings::load (void)
     if (key_char && *key_char != '\0')
         m_encoding = key_char;
     else
-        "UTF-8";
+        m_encoding = "UTF-8";
     m_load_error |= handle_load_error (&key_error, group);
     if (key_char)
         g_free (key_char);
diff --git a/src/import-export/csv-imp/gnc-csv-trans-settings.hpp b/src/import-export/csv-imp/gnc-csv-trans-settings.hpp
index 490eb66..6bcb4a4 100644
--- a/src/import-export/csv-imp/gnc-csv-trans-settings.hpp
+++ b/src/import-export/csv-imp/gnc-csv-trans-settings.hpp
@@ -75,9 +75,6 @@ void remove (void);
  *  The internally generated presets are read-only. The others
  *  can be saved to the state file or deleted.
  *
- *  @param group The group name where the settings are stored in the
- *  key file.
- *
  *  @return true if there was a problem.
  */
 bool read_only (void);
@@ -89,8 +86,8 @@ std::string   m_encoding;                     // File encoding
 bool          m_multi_split;                  // Assume multiple lines per transaction
 int           m_date_format;                  // Date Active id
 int           m_currency_format;              // Currency Active id
-uint32_t          m_skip_start_lines;             // Number of header rows to skip
-uint32_t          m_skip_end_lines;               // Number of footer rows to skip
+uint32_t      m_skip_start_lines;             // Number of header rows to skip
+uint32_t      m_skip_end_lines;               // Number of footer rows to skip
 bool          m_skip_alt_lines;               // Skip alternate rows
 std::string   m_separators;                   // Separators for csv format
 
diff --git a/src/import-export/csv-imp/gnc-tx-import.cpp b/src/import-export/csv-imp/gnc-tx-import.cpp
index 2e102d4..7dbaff8 100644
--- a/src/import-export/csv-imp/gnc-tx-import.cpp
+++ b/src/import-export/csv-imp/gnc-tx-import.cpp
@@ -59,7 +59,6 @@ const gchar* currency_format_user[] = {N_("Locale"),
 
 
 /** Constructor for GncTxImport.
- * @return Pointer to a new GncCSvParseData
  */
 GncTxImport::GncTxImport(GncImpFileFormat format)
 {
@@ -139,7 +138,7 @@ GncImpFileFormat GncTxImport::file_format()
  *  will force a reparsing of the transaction properties (if there are
  *  any) by resetting the first column with a transaction property
  *  it encounters.
- * @param multi_split_val Boolean value with desired state (multi-split
+ * @param multi_split Boolean value with desired state (multi-split
  * vs two-split).
  */
 void GncTxImport::multi_split (bool multi_split)
@@ -172,7 +171,7 @@ bool GncTxImport::multi_split () { return m_settings.m_multi_split; }
  *  in the import data.
  *  In multi-split mode the user has to select an account column so in
  *  that mode the base_account can't be set.
- * @param base_acct Pointer to an account or NULL.
+ * @param base_account Pointer to an account or NULL.
  */
 void GncTxImport::base_account (Account* base_account)
 {
@@ -194,7 +193,7 @@ void GncTxImport::base_account (Account* base_account)
 
         /* Set default account for each line's split properties */
         for (auto line : m_parsed_lines)
-            std::get<3>(line)->set_account (m_settings.m_base_account);
+            std::get<PL_PRESPLIT>(line)->set_account (m_settings.m_base_account);
 
 
     }
@@ -276,12 +275,12 @@ void GncTxImport::update_skipped_lines(boost::optional<uint32_t> start, boost::o
 
     for (uint32_t i = 0; i < m_parsed_lines.size(); i++)
     {
-        std::get<4>(m_parsed_lines[i]) =
+        std::get<PL_SKIP>(m_parsed_lines[i]) =
             ((i < skip_start_lines()) ||             // start rows to skip
              (i >= m_parsed_lines.size() - skip_end_lines()) ||          // end rows to skip
              (((i - skip_start_lines()) % 2 == 1) && // skip every second row...
                   skip_alt_lines()) ||                   // ...if requested
-             (m_skip_errors && !std::get<1>(m_parsed_lines[i]).empty())); // skip lines with errors
+             (m_skip_errors && !std::get<PL_ERROR>(m_parsed_lines[i]).empty())); // skip lines with errors
     }
 }
 
@@ -425,7 +424,7 @@ void GncTxImport::tokenize (bool guessColTypes)
     if (m_settings.m_base_account)
     {
         for (auto line : m_parsed_lines)
-            std::get<3>(line)->set_account (m_settings.m_base_account);
+            std::get<PL_PRESPLIT>(line)->set_account (m_settings.m_base_account);
     }
 
     if (guessColTypes)
@@ -539,7 +538,7 @@ std::string GncTxImport::verify ()
     auto have_line_errors = false;
     for (auto line : m_parsed_lines)
     {
-        if (!std::get<4>(line) && !std::get<1>(line).empty())
+        if (!std::get<PL_SKIP>(line) && !std::get<PL_ERROR>(line).empty())
         {
             have_line_errors = true;
             break;
@@ -720,7 +719,7 @@ void GncTxImport::create_transactions ()
             ++parsed_lines_it)
     {
         /* Skip current line if the user specified so */
-        if ((std::get<4>(*parsed_lines_it)))
+        if ((std::get<PL_SKIP>(*parsed_lines_it)))
             continue;
 
         /* Should not throw anymore, otherwise verify needs revision */
@@ -743,11 +742,11 @@ void GncTxImport::update_pre_trans_props (uint32_t row, uint32_t col, GncTransPr
     if ((prop_type == GncTransPropType::NONE) || (prop_type > GncTransPropType::TRANS_PROPS))
         return; /* Only deal with transaction related properties. */
 
-    auto trans_props = std::make_shared<GncPreTrans> (*(std::get<2>(m_parsed_lines[row])).get());
+    auto trans_props = std::make_shared<GncPreTrans> (*(std::get<PL_PRETRANS>(m_parsed_lines[row])).get());
     auto value = std::string();
 
-    if (col < std::get<0>(m_parsed_lines[row]).size())
-        value = std::get<0>(m_parsed_lines[row]).at(col);
+    if (col < std::get<PL_INPUT>(m_parsed_lines[row]).size())
+        value = std::get<PL_INPUT>(m_parsed_lines[row]).at(col);
 
     if (value.empty())
         trans_props->reset (prop_type);
@@ -762,13 +761,13 @@ void GncTxImport::update_pre_trans_props (uint32_t row, uint32_t col, GncTransPr
             /* Do nothing, just prevent the exception from escalating up
              * However log the error if it happens on a row that's not skipped
              */
-            if (!std::get<4>(m_parsed_lines[row]))
+            if (!std::get<PL_SKIP>(m_parsed_lines[row]))
                 PINFO("User warning: %s", e.what());
         }
     }
 
     /* Store the result */
-    std::get<2>(m_parsed_lines[row]) = trans_props;
+    std::get<PL_PRETRANS>(m_parsed_lines[row]) = trans_props;
 
     /* For multi-split input data, we need to check whether this line is part of
      * a transaction that has already been started by a previous line. */
@@ -779,7 +778,7 @@ void GncTxImport::update_pre_trans_props (uint32_t row, uint32_t col, GncTransPr
             /* This line is part of an already started transaction
              * continue with that one instead to make sure the split from this line
              * gets added to the proper transaction */
-            std::get<2>(m_parsed_lines[row]) = m_parent;
+            std::get<PL_PRETRANS>(m_parsed_lines[row]) = m_parent;
         }
         else
         {
@@ -796,11 +795,11 @@ void GncTxImport::update_pre_split_props (uint32_t row, uint32_t col, GncTransPr
     if ((prop_type > GncTransPropType::SPLIT_PROPS) || (prop_type <= GncTransPropType::TRANS_PROPS))
         return; /* Only deal with split related properties. */
 
-    auto split_props = std::get<3>(m_parsed_lines[row]);
+    auto split_props = std::get<PL_PRESPLIT>(m_parsed_lines[row]);
     auto value = std::string();
 
-    if (col < std::get<0>(m_parsed_lines[row]).size())
-        value = std::get<0>(m_parsed_lines[row]).at(col);
+    if (col < std::get<PL_INPUT>(m_parsed_lines[row]).size())
+        value = std::get<PL_INPUT>(m_parsed_lines[row]).at(col);
 
     if (value.empty())
         split_props->reset (prop_type);
@@ -815,7 +814,7 @@ void GncTxImport::update_pre_split_props (uint32_t row, uint32_t col, GncTransPr
             /* Do nothing, just prevent the exception from escalating up
              * However log the error if it happens on a row that's not skipped
              */
-            if (!std::get<4>(m_parsed_lines[row]))
+            if (!std::get<PL_SKIP>(m_parsed_lines[row]))
                 PINFO("User warning: %s", e.what());
         }
     }
@@ -851,9 +850,9 @@ GncTxImport::set_column_type (uint32_t position, GncTransPropType type, bool for
         /* Reset date and currency formats for each trans/split props object
          * to ensure column updates use the most recent one
          */
-        std::get<2>(*parsed_lines_it)->set_date_format (m_settings.m_date_format);
-        std::get<3>(*parsed_lines_it)->set_date_format (m_settings.m_date_format);
-        std::get<3>(*parsed_lines_it)->set_currency_format (m_settings.m_currency_format);
+        std::get<PL_PRETRANS>(*parsed_lines_it)->set_date_format (m_settings.m_date_format);
+        std::get<PL_PRESPLIT>(*parsed_lines_it)->set_date_format (m_settings.m_date_format);
+        std::get<PL_PRESPLIT>(*parsed_lines_it)->set_currency_format (m_settings.m_currency_format);
 
         uint32_t row = parsed_lines_it - m_parsed_lines.begin();
 
@@ -862,7 +861,7 @@ GncTxImport::set_column_type (uint32_t position, GncTransPropType type, bool for
          */
         if (old_type != type)
         {
-            auto old_col = std::get<0>(*parsed_lines_it).size(); // Deliberately out of bounds to trigger a reset!
+            auto old_col = std::get<PL_INPUT>(*parsed_lines_it).size(); // Deliberately out of bounds to trigger a reset!
             if ((old_type > GncTransPropType::NONE)
                     && (old_type <= GncTransPropType::TRANS_PROPS))
                 update_pre_trans_props (row, old_col, old_type);
@@ -880,9 +879,9 @@ GncTxImport::set_column_type (uint32_t position, GncTransPropType type, bool for
             update_pre_split_props (row, position, type);
 
         /* Report errors if there are any */
-        auto trans_errors = std::get<2>(*parsed_lines_it)->errors();
-        auto split_errors = std::get<3>(*parsed_lines_it)->errors(m_req_mapped_accts);
-        std::get<1>(*parsed_lines_it) =
+        auto trans_errors = std::get<PL_PRETRANS>(*parsed_lines_it)->errors();
+        auto split_errors = std::get<PL_PRESPLIT>(*parsed_lines_it)->errors(m_req_mapped_accts);
+        std::get<PL_ERROR>(*parsed_lines_it) =
                 trans_errors +
                 (trans_errors.empty() && split_errors.empty() ? std::string() : "\n") +
                 split_errors;
@@ -907,14 +906,13 @@ GncTxImport::accounts ()
     uint32_t tacct_col = tacct_col_it - m_settings.m_column_types.begin();
 
     /* Iterate over all parsed lines */
-    auto odd_line = false;
     for (auto parsed_line : m_parsed_lines)
     {
         /* Skip current line if the user specified so */
-        if ((std::get<4>(parsed_line)))
+        if ((std::get<PL_SKIP>(parsed_line)))
             continue;
 
-        auto col_strs = std::get<0>(parsed_line);
+        auto col_strs = std::get<PL_INPUT>(parsed_line);
         if ((acct_col_it != m_settings.m_column_types.end()) && !col_strs[acct_col].empty())
             accts.insert(col_strs[acct_col]);
         if ((tacct_col_it != m_settings.m_column_types.end()) && !col_strs[tacct_col].empty())
diff --git a/src/import-export/csv-imp/gnc-tx-import.hpp b/src/import-export/csv-imp/gnc-tx-import.hpp
index c763827..c9eb8ca 100644
--- a/src/import-export/csv-imp/gnc-tx-import.hpp
+++ b/src/import-export/csv-imp/gnc-tx-import.hpp
@@ -73,6 +73,11 @@ extern const gchar* date_format_user[];
  *  - an optional error string
  *  - a struct to hold user selected properties for a transaction
  *  - a struct to hold user selected properties for one or two splits in the above transaction */
+#define PL_INPUT    0
+#define PL_ERROR    1
+#define PL_PRETRANS 2
+#define PL_PRESPLIT 3
+#define PL_SKIP     4
 using parse_line_t = std::tuple<StrVec,
                                 std::string,
                                 std::shared_ptr<GncPreTrans>,

commit b7bcd792f6e4ff050c26c5ceeab3606b4581eebb
Author: Geert Janssens <geert at kobaltwit.be>
Date:   Fri Apr 28 18:25:34 2017 +0200

    Align cmake rational/numeric test invocation with Makefile based one
    
    This invocation avoids linking in gnc-qof and instead will
    directly pull in all sources required.

diff --git a/src/libqof/qof/test/CMakeLists.txt b/src/libqof/qof/test/CMakeLists.txt
index 1e9ab7d..0b1cdf7 100644
--- a/src/libqof/qof/test/CMakeLists.txt
+++ b/src/libqof/qof/test/CMakeLists.txt
@@ -50,9 +50,18 @@ IF (NOT WIN32)
   GNC_ADD_TEST(test-qof "${test_qof_SOURCES}" TEST_QOF_INCLUDE_DIRS TEST_QOF_LIBS)
   TARGET_COMPILE_DEFINITIONS(test-qof PRIVATE TESTPROG=test_qof)
   SET(MODULEPATH ${CMAKE_SOURCE_DIR}/src/libqof/qof)
-  SET(gtest_qof_LIBS gnc-qof ${GLIB2_LDFLAGS} ${Boost_LIBRARIES} ${GTEST_LIB})
+  SET(gtest_old_qof_LIBS gnc-qof ${GLIB2_LDFLAGS} ${Boost_LIBRARIES} ${GTEST_LIB})
+  SET(gtest_qof_LIBS
+    ${GLIB2_LDFLAGS}
+    ${GOBJECT_LDFLAGS}
+    ${GMODULE_LDFLAGS}
+    ${GTHREAD_LDFLAGS}
+    ${Boost_LIBRARIES}
+    ${GTEST_LIB})
   SET(gtest_qof_INCLUDES
     ${MODULEPATH}
+    ${CMAKE_BINARY_DIR}/src # for config.h
+    ${CMAKE_SOURCE_DIR}/src # for platform.h
     ${GLIB2_INCLUDE_DIRS}
     ${GTEST_INCLUDE_DIR})
 
@@ -61,7 +70,7 @@ IF (NOT WIN32)
     test-gnc-guid.cpp
     ${GTEST_SRC})
   GNC_ADD_TEST(test-gnc-guid "${test_gnc_guid_SOURCES}"
-    gtest_qof_INCLUDES gtest_qof_LIBS)
+    gtest_qof_INCLUDES gtest_old_qof_LIBS)
 
   SET(test_kvp_value_SOURCES
     ${MODULEPATH}/kvp-value.cpp
@@ -69,14 +78,14 @@ IF (NOT WIN32)
     test-kvp-frame.cpp
     ${GTEST_SRC})
   GNC_ADD_TEST(test-kvp-value "${test_kvp_value_SOURCES}"
-    gtest_qof_INCLUDES gtest_qof_LIBS)
+    gtest_qof_INCLUDES gtest_old_qof_LIBS)
 
   SET(test_qofsession_SOURCES
     ${MODULEPATH}/qofsession.cpp
     test-qofsession.cpp
     ${GTEST_SRC})
   GNC_ADD_TEST(test-qofsession "${test_qofsession_SOURCES}"
-    gtest_qof_INCLUDES gtest_qof_LIBS)
+    gtest_qof_INCLUDES gtest_old_qof_LIBS)
 
   SET(test_gnc_int128_SOURCES
     ${MODULEPATH}/gnc-int128.cpp
@@ -87,13 +96,25 @@ IF (NOT WIN32)
 
   SET(test_gnc_rational_SOURCES
     ${MODULEPATH}/gnc-rational.cpp
+    ${MODULEPATH}/gnc-numeric.cpp
+    ${MODULEPATH}/gnc-int128.cpp
+    ${MODULEPATH}/gnc-datetime.cpp
+    ${MODULEPATH}/gnc-timezone.cpp
+    ${MODULEPATH}/gnc-date.cpp
+    ${MODULEPATH}/qoflog.cpp
     gtest-gnc-rational.cpp
     ${GTEST_SRC})
   GNC_ADD_TEST(test-gnc-rational "${test_gnc_rational_SOURCES}"
     gtest_qof_INCLUDES gtest_qof_LIBS)
 
   SET(test_gnc_numeric_SOURCES
+    ${MODULEPATH}/gnc-rational.cpp
+    ${MODULEPATH}/gnc-int128.cpp
     ${MODULEPATH}/gnc-numeric.cpp
+    ${MODULEPATH}/gnc-datetime.cpp
+    ${MODULEPATH}/gnc-timezone.cpp
+    ${MODULEPATH}/gnc-date.cpp
+    ${MODULEPATH}/qoflog.cpp
     gtest-gnc-numeric.cpp
     ${GTEST_SRC})
   GNC_ADD_TEST(test-gnc-numeric "${test_gnc_numeric_SOURCES}"
@@ -104,12 +125,12 @@ IF (NOT WIN32)
     gtest-gnc-timezone.cpp
     ${GTEST_SRC})
   GNC_ADD_TEST(test-gnc-timezone "${test_gnc_timezone_SOURCES}"
-    gtest_qof_INCLUDES gtest_qof_LIBS)
+    gtest_qof_INCLUDES gtest_old_qof_LIBS)
 
   SET(test_gnc_datetime_SOURCES
     ${MODULEPATH}/gnc-datetime.cpp
     gtest-gnc-datetime.cpp
     ${GTEST_SRC})
   GNC_ADD_TEST(test-gnc-datetime "${test_gnc_datetime_SOURCES}"
-    gtest_qof_INCLUDES gtest_qof_LIBS)
+    gtest_qof_INCLUDES gtest_old_qof_LIBS)
 ENDIF()

commit b5530bd41fd2d2cc4b738fdfcdd139f17bae49ce
Author: Geert Janssens <geert at kobaltwit.be>
Date:   Wed Apr 26 10:59:46 2017 +0200

    Fix autotools based build
    
    For some reason gnc-vcs-info.h isn't found properly any more although
    the relevant parts of the Makefiles haven't changed compared to the
    maint branch. Perhaps a compiler option has changed ? Anyway simply
    adding its path explicitly does fix it.

diff --git a/src/bin/Makefile.am b/src/bin/Makefile.am
index c85a63d..d52fdf1 100644
--- a/src/bin/Makefile.am
+++ b/src/bin/Makefile.am
@@ -16,6 +16,7 @@ AM_CPPFLAGS = -I${top_builddir} ${GLIB_CFLAGS} ${GNOME_CFLAGS} ${GTK_CFLAGS} \
   -I${top_srcdir}/src/engine \
   -I${top_srcdir}/src/gnome \
   -I${top_builddir}/src \
+  -I${top_builddir}/src/core-utils \
   -I${top_srcdir}/src/gnc-module \
   -I${top_srcdir}/src/libqof/qof \
   -I${top_srcdir}/src/report/report-system \
diff --git a/src/gnome-utils/Makefile.am b/src/gnome-utils/Makefile.am
index 8593462..d11c762 100644
--- a/src/gnome-utils/Makefile.am
+++ b/src/gnome-utils/Makefile.am
@@ -12,6 +12,7 @@ AM_CPPFLAGS = \
   -I${top_srcdir}/src/app-utils \
   -I${top_srcdir}/src \
   -I${top_builddir}/src \
+  -I${top_builddir}/src/core-utils \
   -I${top_srcdir}/lib/libc \
   -I${top_srcdir}/src/libqof/qof \
   ${GLIB_CFLAGS} \



Summary of changes:
 src/bin/Makefile.am                                |   1 +
 src/engine/test/test-date.cpp                      |   6 +-
 src/engine/test/utest-gnc-pricedb.c                |   7 +
 src/gnome-utils/Makefile.am                        |   1 +
 .../csv-imp/assistant-csv-trans-import.cpp         |  16 +--
 .../csv-imp/gnc-csv-trans-settings.cpp             |   2 +-
 .../csv-imp/gnc-csv-trans-settings.hpp             |   7 +-
 src/import-export/csv-imp/gnc-tx-import.cpp        |  56 ++++----
 src/import-export/csv-imp/gnc-tx-import.hpp        |  16 ++-
 src/libqof/qof/gnc-date.cpp                        |  76 +++--------
 src/libqof/qof/gnc-datetime.cpp                    | 122 ++++++++++++++++-
 src/libqof/qof/gnc-datetime.hpp                    |  79 ++++++++++-
 src/libqof/qof/test/CMakeLists.txt                 |  34 ++++-
 src/libqof/qof/test/Makefile.am                    |   7 +-
 src/libqof/qof/test/gtest-gnc-datetime.cpp         | 148 ++++++++++++++++++++-
 src/libqof/qof/test/test-gnc-date.c                |  45 +++++--
 16 files changed, 492 insertions(+), 131 deletions(-)



More information about the gnucash-changes mailing list