Index: goffice/utils/formats.c
===================================================================
--- goffice/utils/formats.c	(revision 2330)
+++ goffice/utils/formats.c	(working copy)
@@ -59,48 +59,9 @@
 	NULL
 };
 
-/*****************************************************************/
-/* Some are generated						 */
-/* WARNING WARNING WARNING : do not reorder these !! 		 */
-/* the generated versions and the excel plugin assume this order */
-static char const *
-fmts_date [] = {
-	"m/d/yy",		/* 0 */
-	"m/d/yyyy",		/* 1 */
-	"d-mmm-yy",		/* 2 */
-	"d-mmm-yyyy",		/* 3 */
-	"d-mmm",		/* 4 */
-	"d-mm",			/* 5 */
-	"mmm/d",		/* 6 */
-	"mm/d",			/* 7 */
-	"mm/dd/yy",		/* 8 */
-	"mm/dd/yyyy",		/* 9 */
-	"mmm/dd/yy",		/* 10 */
-	"mmm/dd/yyyy",		/* 11 */
-	"mmm/ddd/yy",		/* 12 */
-	"mmm/ddd/yyyy",		/* 13 */
-	"mm/ddd/yy",		/* 14 */
-	"mm/ddd/yyyy",		/* 15 */
-	"mmm-yy",		/* 16 */
-	"mmm-yyyy",		/* 17 */
-	"mmmm-yy",		/* 18 */
-	"mmmm-yyyy",		/* 19 */
-	"m/d/yy h:mm",		/* 20 */
-	"m/d/yyyy h:mm",	/* 21 */
-	"yyyy/mm/d",		/* 22 */
-	"yyyy/mmm/d",		/* 23 */
-	"yyyy/mm/dd",		/* 24 */
-	"yyyy/mmm/dd",		/* 25 */
-	"yyyy-mm-d",		/* 26 */
-	"yyyy-mmm-d",		/* 27 */
-	"yyyy-mm-dd",		/* 28 */
-	"yyyy-mmm-dd",		/* 29 */
-	"yy",			/* 30 */
-	"yyyy",			/* 31 */
-	"mmmmm",		/* 32 stored as custom in xls */
-	"mmmmm-yy",		/* 33 stored as custom in xls */
-	NULL
-};
+/* All are generated.  */
+static char const *fmts_date[50];
+static gunichar date_sep;
 
 /*****************************************************/
 
@@ -177,12 +138,87 @@
 	NULL                      /* GO_FORMAT_MARKUP */
 };
 
+static void
+add_date_format (GHashTable *date_hash, guint *ndates, const char *fmt)
+{
+	char *fmt2;
+
+	if (g_hash_table_lookup (date_hash, fmt))
+		return;
+
+	g_assert (*ndates + 1 < G_N_ELEMENTS (fmts_date));
+	fmt2 = g_strdup (fmt);
+	fmts_date[*ndates] = fmt2;
+	g_hash_table_insert (date_hash, fmt2, fmt2);
+	(*ndates)++;
+	fmts_date[*ndates] = NULL;	
+}
+
+static void
+add_frobbed_date_format (GHashTable *date_hash, guint *ndates, const char *fmt)
+{
+	GString *s = g_string_new (NULL);
+
+	while (*fmt) {
+		if (*fmt == '/') {
+			g_string_append_unichar (s, date_sep);
+		} else
+			g_string_append_c (s, *fmt);
+		fmt++;
+	}
+
+	add_date_format (date_hash, ndates, s->str);
+	g_string_free (s, TRUE);
+}
+
+static void
+add_dmy_formats (GHashTable *date_hash, guint *ndates)
+{
+	add_frobbed_date_format (date_hash, ndates, "dd/mm/yyyy");
+	add_frobbed_date_format (date_hash, ndates, "dd/mm");
+}
+
+static void
+add_mdy_formats (GHashTable *date_hash, guint *ndates)
+{
+	add_frobbed_date_format (date_hash, ndates, "m/d/yyyy");
+	add_frobbed_date_format (date_hash, ndates, "m/d");
+}
+
+/* Very hacky.  Sorry.  */
+static gunichar
+guess_date_sep (void)
+{
+	const GString *df = go_locale_get_date_format();
+	const char *s;
+
+	for (s = df->str; *s; s++) {
+		switch (*s) {
+		case 'd': case 'm': case 'y':
+			while (g_ascii_isalpha (*s))
+				s++;
+			while (g_unichar_isspace (g_utf8_get_char (s)))
+				s = g_utf8_next_char (s);
+			if (*s != ',' &&
+			    g_unichar_ispunct (g_utf8_get_char (s)))
+				return g_utf8_get_char (s);
+			break;
+		default:
+			; /* Nothing */
+		}
+	}
+
+	return '/';
+}
+
 void
 go_currency_date_format_init (void)
 {
 	gboolean precedes, space_sep;
 	char const *curr = go_locale_get_currency (&precedes, &space_sep)->str;
 	char *pre, *post, *pre_rep, *post_rep;
+	GHashTable *date_hash;
+	guint ndates;
 
 	/*
 	 *  1. "$*  "	Yes, it is needed (because we use match[])
@@ -239,49 +275,40 @@
 
 	g_free (*pre ? pre : post);
 
-	if (!go_locale_month_before_day ()) {
-		fmts_date [0]  = "d/m/yy";
-		fmts_date [1]  = "d/m/yyyy";
-		fmts_date [2]  = "mmm-d-yy";
-		fmts_date [3]  = "mmm-d-yyyy";
-		fmts_date [4]  = "mmm-d";
-		fmts_date [5]  = "mm-d";
-		fmts_date [6]  = "d/mmm";
-		fmts_date [7]  = "d/mm";
-		fmts_date [8]  = "dd/mm/yy";
-		fmts_date [9]  = "dd/mm/yyyy";
-		fmts_date [10] = "dd/mmm/yy";
-		fmts_date [11] = "dd/mmm/yyyy";
-		fmts_date [12] = "ddd/mmm/yy";
-		fmts_date [13] = "ddd/mmm/yyyy";
-		fmts_date [14] = "ddd/mm/yy";
-		fmts_date [15] = "ddd/mm/yyyy";
-		fmts_date [20] = "d/m/yy h:mm";
-		fmts_date [21] = "d/m/yyyy h:mm";
+	/* ---------------------------------------- */
 
-		fmts_time [4]  = "d/m/yy h:mm";
-	} else {
-		fmts_date [0]  = "m/d/yy";
-		fmts_date [1]  = "m/d/yyyy";
-		fmts_date [2]  = "d-mmm-yy";
-		fmts_date [3]  = "d-mmm-yyyy";
-		fmts_date [4]  = "d-mmm";
-		fmts_date [5]  = "d-mm";
-		fmts_date [6]  = "mmm/d";
-		fmts_date [7]  = "mm/d";
-		fmts_date [8]  = "mm/dd/yy";
-		fmts_date [9]  = "mm/dd/yyyy";
-		fmts_date [10] = "mmm/dd/yy";
-		fmts_date [11] = "mmm/dd/yyyy";
-		fmts_date [12] = "mmm/ddd/yy";
-		fmts_date [13] = "mmm/ddd/yyyy";
-		fmts_date [14] = "mm/ddd/yy";
-		fmts_date [15] = "mm/ddd/yyyy";
-		fmts_date [20] = "m/d/yy h:mm";
-		fmts_date [21] = "m/d/yyyy h:mm";
+	date_sep = guess_date_sep ();
+	date_hash = g_hash_table_new (g_str_hash, g_str_equal);
+	ndates = 0;
 
-		fmts_time [4]  = "m/d/yy h:mm";
+	switch (go_locale_month_before_day ()) {
+	case 0:
+		add_dmy_formats (date_hash, &ndates);
+		break;
+	default:
+	case 1:
+		add_mdy_formats (date_hash, &ndates);
+		break;
+	case 2:
+		add_date_format (date_hash, &ndates, "yyyy/mm/dd");
+		add_mdy_formats (date_hash, &ndates);
+		break;
 	}
+
+	/* Make sure these exist no matter what.  */
+	add_date_format (date_hash, &ndates, "m/d/yyyy");
+	add_date_format (date_hash, &ndates, "m/d/yy");
+	add_date_format (date_hash, &ndates, "dd/mm/yyyy");
+	add_date_format (date_hash, &ndates, "dd/mm/yy");
+	add_date_format (date_hash, &ndates, "d-mmm-yyyy");
+
+	{
+		char *s = g_strconcat (fmts_date[0], " h:mm", NULL);
+		add_date_format (date_hash, &ndates, s);
+		g_free (s);
+	}
+
+	g_hash_table_destroy (date_hash);
 }
 
 void
@@ -302,6 +329,11 @@
 	fmts_accounting [0] = NULL;
 	g_free ((char *)(fmts_accounting[2]));
 	fmts_accounting[2] = NULL;
+
+	for (i = 0; fmts_date[i]; i++) {
+		g_free ((char*)(fmts_date[i]));
+		fmts_date[i] = NULL;
+	}
 }
 
 GOFormatCurrency const go_format_currencies[] =
