Merge branch 'gdate-parse-month' into 'master'

gdate: Use longest matching month name in g_date_set_parse

Closes #1343

See merge request GNOME/glib!433
This commit is contained in:
Philip Withnall 2018-11-13 15:00:36 +00:00
commit 9e5a8ba22e
2 changed files with 65 additions and 44 deletions

View File

@ -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 (update_month_match (&longest, normalized, short_month_names[i]))
pt->month = i;
if (found != NULL)
{
pt->month = i;
break;
}
}
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);

View File

@ -208,6 +208,39 @@ test_parse_locale_change (void)
setlocale (LC_ALL, "");
}
static void
test_month_substring (void)
{
GDate date;
g_test_bug ("793550");
if (setlocale (LC_ALL, "pl_PL") == NULL)
{
g_test_skip ("pl_PL locale not available");
return;
}
/* In Polish language September is "wrzesień" and August is "sierpień"
* abbreviated as "sie". The former used to be confused with the latter
* because "sie" is a substring of "wrzesień" and was matched first. */
g_date_set_parse (&date, "wrzesień 2018");
g_assert_true (g_date_valid (&date));
g_assert_cmpint (g_date_get_month (&date), ==, G_DATE_SEPTEMBER);
g_date_set_parse (&date, "sie 2018");
g_assert_true (g_date_valid (&date));
g_assert_cmpint (g_date_get_month (&date), ==, G_DATE_AUGUST);
g_date_set_parse (&date, "sierpień 2018");
g_assert_true (g_date_valid (&date));
g_assert_cmpint (g_date_get_month (&date), ==, G_DATE_AUGUST);
setlocale (LC_ALL, "");
}
static void
test_month_names (void)
{
@ -736,6 +769,7 @@ main (int argc, char** argv)
g_test_add_func ("/date/dates", test_dates);
g_test_add_func ("/date/parse", test_parse);
g_test_add_func ("/date/parse_locale_change", test_parse_locale_change);
g_test_add_func ("/date/month_substring", test_month_substring);
g_test_add_func ("/date/month_names", test_month_names);
g_test_add_func ("/date/clamp", test_clamp);
g_test_add_func ("/date/order", test_order);