r16317 - gnucash/branches/csv-import/src/import-export/csv - Rewrote parse_date to be separator agnostic

Benjamin Sperisen lasindi at cvs.gnucash.org
Sun Jul 15 21:51:36 EDT 2007


Author: lasindi
Date: 2007-07-15 21:51:35 -0400 (Sun, 15 Jul 2007)
New Revision: 16317
Trac: http://svn.gnucash.org/trac/changeset/16317

Modified:
   gnucash/branches/csv-import/src/import-export/csv/example-file.csv
   gnucash/branches/csv-import/src/import-export/csv/gnc-csv-import.c
   gnucash/branches/csv-import/src/import-export/csv/gnc-csv-model.c
   gnucash/branches/csv-import/src/import-export/csv/gnc-csv-model.h
Log:
Rewrote parse_date to be separator agnostic


Modified: gnucash/branches/csv-import/src/import-export/csv/example-file.csv
===================================================================
--- gnucash/branches/csv-import/src/import-export/csv/example-file.csv	2007-07-15 22:40:12 UTC (rev 16316)
+++ gnucash/branches/csv-import/src/import-export/csv/example-file.csv	2007-07-16 01:51:35 UTC (rev 16317)
@@ -1,4 +1,4 @@
 "This file has colon separators":100:01/03/95
-"and the last line":-50:02/28/96
-"uses a different form":-25.13:03/15/00
-"of date separator.":12.5:04-30-02
+"and the last line":-50:02.28.96
+"uses a different":-25.13:03/15/00
+"date format.":12.5:30-4-02

Modified: gnucash/branches/csv-import/src/import-export/csv/gnc-csv-import.c
===================================================================
--- gnucash/branches/csv-import/src/import-export/csv/gnc-csv-import.c	2007-07-15 22:40:12 UTC (rev 16316)
+++ gnucash/branches/csv-import/src/import-export/csv/gnc-csv-import.c	2007-07-16 01:51:35 UTC (rev 16317)
@@ -778,8 +778,12 @@
                                    trans_line->trans);
       transactions = g_list_next(transactions);
     }
-    /* Let the user load those transactions into the account. */
-    gnc_gen_trans_list_run(gnc_csv_importer_gui);
+    /* Let the user load those transactions into the account, so long
+     * as there is at least one transaction to be loaded. */
+    if(parse_data->transactions != NULL)
+      gnc_gen_trans_list_run(gnc_csv_importer_gui);
+    else
+      gnc_gen_trans_list_delete(gnc_csv_importer_gui);
 
     /* Free the memory we allocated. */
     gnc_csv_preview_free(preview);

Modified: gnucash/branches/csv-import/src/import-export/csv/gnc-csv-model.c
===================================================================
--- gnucash/branches/csv-import/src/import-export/csv/gnc-csv-model.c	2007-07-15 22:40:12 UTC (rev 16316)
+++ gnucash/branches/csv-import/src/import-export/csv/gnc-csv-model.c	2007-07-16 01:51:35 UTC (rev 16317)
@@ -11,6 +11,7 @@
 #include <sys/mman.h>
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <regex.h>
 #include <unistd.h>
 #include <fcntl.h>
 #include <stdlib.h>
@@ -18,26 +19,11 @@
 
 static QofLogModule log_module = GNC_MOD_IMPORT;
 
-const int num_date_formats = 8;
-/* A set of date formats that the user sees. */
-const gchar* date_format_user[] = {N_("yyyy/mm/dd"),
-                                   N_("yy/mm/dd"),
-                                   N_("dd/mm/yyyy"),
-                                   N_("dd/mm/yy"),
-                                   N_("dd/mm/yyyy"),
-                                   N_("dd/mm/yy"),
-                                   N_("mm/dd/yyyy"),
-                                   N_("mm/dd/yy")};
+const int num_date_formats = 3;
 
-/* Matching formats for date_format_user to be used with strptime. */
-const gchar* date_format_internal[] = {"%Y/%m/%d",
-                                       "%y/%m/%d",
-                                       "%d/%m/%Y",
-                                       "%d/%m/%y",
-                                       "%d/%m/%Y",
-                                       "%d/%m/%y",
-                                       "%m/%d/%Y",
-                                       "%m/%d/%y"};
+const gchar* date_format_user[] = {N_("y-d-m"),
+                                   N_("d-m-y"),
+                                   N_("m-d-y")};
 
 /** A set of sensible defaults for parsing CSV files. 
  * @return StfParseOptions_t* for parsing a file with comma separators
@@ -50,24 +36,108 @@
   return options;
 }
 
-/* TODO This will be replaced by something more sophisticated. */
-/* TODO Comment. */
+/** Parses a string into a date, given a format. This function
+ * requires only knowing the order in which the year, month and day
+ * appear. For example, 01-02-2003 will be parsed the same way as
+ * 01/02/2003.
+ * @param date_str The string containing a date being parsed
+ * @param format An index specifying a format in date_format_user
+ * @return The parsed value of date_str on success or -1 on failure
+ */
 static time_t parse_date(const char* date_str, int format)
 {
-  struct tm retvalue;
-  char *last_parsed_char;
-  last_parsed_char = strptime(date_str, date_format_internal[format], &retvalue);
-  if(last_parsed_char != date_str + strlen(date_str))
+  time_t rawtime; /* The integer time */
+  struct tm retvalue; /* The time in a broken-down structure */
+  
+  int i, j, mem_length, orig_year, orig_month, orig_day;
+
+  /* Buffer for containing individual parts (e.g. year, month, day) of a date */
+  char date_segment[5];
+
+  /* The compiled regular expression */
+  regex_t preg = {0};
+
+  /* An array containing indices specifying the matched substrings in date_str */
+  regmatch_t pmatch[4] = { {0}, {0}, {0}, {0} };
+
+  /* The regular expression for parsing dates */
+  const char* regex = "^ *([0-9]+) *[-/.'] *([0-9]+) *[-/.'] *([0-9]+).*$|^ *([0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]).*$";
+
+  /* We get our matches using the regular expression. */
+  regcomp(&preg, regex, REG_EXTENDED);
+  regexec(&preg, date_str, 4, pmatch, 0);
+  regfree(&preg);
+
+  /* If there wasn't a match, there was an error. */
+  if(pmatch[0].rm_eo == 0)
+    return -1;
+
+  /* Put some sane values in retvalue by using the current time for
+   * the non-year-month-day parts of the date. */
+  time(&rawtime);
+  localtime_r(&rawtime, &retvalue);
+
+  /* j traverses pmatch (index 0 contains the entire string, so we
+   * start at index 1 for the first meaningful match). */
+  j = 1;
+  /* Go through the date format and interpret the matches in order of
+   * the sections in the date format. */
+  for(i = 0; date_format_user[format][i]; i++)
   {
+    char segment_type = date_format_user[format][i];
+    /* Only do something if this is a meaningful character */
+    if(segment_type == 'y' || segment_type == 'm' || segment_type == 'd')
+    {
+      /* Copy the matching substring into date_segment so that we can
+       * convert it into an integer. */
+      mem_length = pmatch[j].rm_eo - pmatch[j].rm_so;
+      memcpy(date_segment, date_str + pmatch[j].rm_so, mem_length);
+      date_segment[mem_length] = '\0';
+
+      /* Set the appropriate member of retvalue. Save the original
+       * values so that we can check if the change when we use mktime
+       * below. */
+      switch(segment_type)
+      {
+      case 'y':
+        retvalue.tm_year = atoi(date_segment);
+
+        /* Handle two-digit years. */
+        if(retvalue.tm_year < 100)
+        {
+          /* We allow two-digit years in the range 1969 - 2068. */
+          if(retvalue.tm_year < 69)
+            retvalue.tm_year += 100;
+        }
+        else
+          retvalue.tm_year -= 1900;
+        orig_year = retvalue.tm_year;
+        break;
+        
+      case 'm':
+        orig_month = retvalue.tm_mon = atoi(date_segment) - 1;
+        break;
+        
+      case 'd':
+        orig_day = retvalue.tm_mday = atoi(date_segment);
+        break;
+      }
+      j++;
+    }
+  }
+  /* Convert back to an integer. If mktime leaves retvalue unchanged,
+   * everything is okay; otherwise, an error has occurred. */
+  rawtime = mktime(&retvalue);
+  if(retvalue.tm_mday == orig_day &&
+     retvalue.tm_mon == orig_month &&
+     retvalue.tm_year == orig_year)
+  {
+    return rawtime;
+  }
+  else
+  {
     return -1;
   }
-  /* We have to set the hour, minute, second and daylight savings time
-   * flags to valid values. */
-  retvalue.tm_hour = 0;
-  retvalue.tm_min = 0;
-  retvalue.tm_sec = 1;
-  retvalue.tm_isdst = -1;
-  return mktime(&retvalue);
 }
 
 /** Constructor for GncCsvParseData.

Modified: gnucash/branches/csv-import/src/import-export/csv/gnc-csv-model.h
===================================================================
--- gnucash/branches/csv-import/src/import-export/csv/gnc-csv-model.h	2007-07-15 22:40:12 UTC (rev 16316)
+++ gnucash/branches/csv-import/src/import-export/csv/gnc-csv-model.h	2007-07-16 01:51:35 UTC (rev 16317)
@@ -76,9 +76,6 @@
 /* A set of date formats that the user sees. */
 extern const gchar* date_format_user[];
 
-/* Matching formats for date_format_user to be used with strptime. */
-extern const gchar* date_format_internal[];
-
 /** Struct containing data for parsing a CSV/Fixed-Width file. */
 typedef struct
 {



More information about the gnucash-changes mailing list