From ba18822f358c49f15435197dba7c11f6753396f1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= <tomasz.miasko@gmail.com>
Date: Tue, 30 Oct 2018 00:00:00 +0000
Subject: [PATCH 258/682] gdate: Use longest matching month name in
 g_date_set_parse

There are languages where a name of one month is a substring of another.
Instead of stopping search on the first match use the month that
constitutes the longest match.

Fixes #1343.
---
 glib/gdate.c      | 75 ++++++++++++++++++++---------------------------
 glib/tests/date.c | 34 +++++++++++++++++++++
 2 files changed, 65 insertions(+), 44 deletions(-)

diff --git a/glib/gdate.c b/glib/gdate.c
index 4925818b3..5457a3b8c 100644
--- a/glib/gdate.c
+++ b/glib/gdate.c
@@ -931,6 +931,27 @@ struct _GDateParseTokens {
 
 typedef struct _GDateParseTokens GDateParseTokens;
 
+static inline gboolean
+update_month_match (gsize *longest,
+                    const gchar *haystack,
+                    const gchar *needle)
+{
+  gsize length;
+
+  if (needle == NULL)
+    return FALSE;
+
+  length = strlen (needle);
+  if (*longest >= length)
+    return FALSE;
+
+  if (strstr (haystack, needle) == NULL)
+    return FALSE;
+
+  *longest = length;
+  return TRUE;
+}
+
 #define NUM_LEN 10
 
 /* HOLDS: g_date_global_lock */
@@ -978,6 +999,7 @@ g_date_fill_parse_tokens (const gchar *str, GDateParseTokens *pt)
   
   if (pt->num_ints < 3)
     {
+      gsize longest = 0;
       gchar *casefold;
       gchar *normalized;
       
@@ -985,8 +1007,7 @@ g_date_fill_parse_tokens (const gchar *str, GDateParseTokens *pt)
       normalized = g_utf8_normalize (casefold, -1, G_NORMALIZE_ALL);
       g_free (casefold);
 
-      i = 1;
-      while (i < 13)
+      for (i = 1; i < 13; ++i)
         {
           /* Here month names may be in a genitive case if the language
            * grammatical rules require it.
@@ -997,60 +1018,26 @@ g_date_fill_parse_tokens (const gchar *str, GDateParseTokens *pt)
            * genitive case here so they use nominative everywhere.
            * For example, English always uses "January".
            */
-          if (long_month_names[i] != NULL) 
-            {
-              const gchar *found = strstr (normalized, long_month_names[i]);
-	      
-              if (found != NULL)
-                {
-                  pt->month = i;
-		  break;
-                }
-            }
+          if (update_month_match (&longest, normalized, long_month_names[i]))
+            pt->month = i;
 
           /* Here month names will be in a nominative case.
            * Examples of how January may look in some languages:
            * Catalan: "gener", Croatian: "Siječanj", Polish: "styczeń",
            * Upper Sorbian: "Januar".
            */
-          if (long_month_names_alternative[i] != NULL)
-            {
-              const gchar *found = strstr (normalized, long_month_names_alternative[i]);
-
-              if (found != NULL)
-                {
-                  pt->month = i;
-                  break;
-                }
-            }
+          if (update_month_match (&longest, normalized, long_month_names_alternative[i]))
+            pt->month = i;
 
           /* Differences between abbreviated nominative and abbreviated
            * genitive month names are visible in very few languages but
            * let's handle them.
            */
-          if (short_month_names[i] != NULL) 
-            {
-              const gchar *found = strstr (normalized, short_month_names[i]);
-	      
-              if (found != NULL)
-                {
-                  pt->month = i;
-		  break;
-                }
-            }
+          if (update_month_match (&longest, normalized, short_month_names[i]))
+            pt->month = i;
 
-          if (short_month_names_alternative[i] != NULL)
-            {
-              const gchar *found = strstr (normalized, short_month_names_alternative[i]);
-
-              if (found != NULL)
-                {
-                  pt->month = i;
-                  break;
-                }
-            }
-
-          ++i;
+          if (update_month_match (&longest, normalized, short_month_names_alternative[i]))
+            pt->month = i;
         }
 
       g_free (normalized);
