>From d387666e4785e4ddbbe4e50849f7c3f335761982 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20=C3=81ngel=20Arruga=20Vivas?= Date: Wed, 9 Dec 2020 21:45:09 +0100 Subject: [PATCH 2/2] format-lisp, format-scheme: Allow omit integer with ngettext. * gettext-tools/src/format-lisp.c (same_elements, is_one_integer_less, compatible_list): New functions. (format_check): Use compatible_list when equality is false. * gettext-tools/src/format-scheme.c (same_elements, is_one_integer_less, compatible_list): New functions. (format_check): Use compatible_list when equality is false. --- gettext-tools/src/format-lisp.c | 91 ++++++++++++++++++++++++++++--- gettext-tools/src/format-scheme.c | 91 ++++++++++++++++++++++++++++--- 2 files changed, 168 insertions(+), 14 deletions(-) diff --git a/gettext-tools/src/format-lisp.c b/gettext-tools/src/format-lisp.c index 94194dbef..bf43309fe 100644 --- a/gettext-tools/src/format-lisp.c +++ b/gettext-tools/src/format-lisp.c @@ -333,6 +333,89 @@ equal_list (const struct format_arg_list *list1, return true; } +static bool +same_elements (const struct segment * s, unsigned int i, + const struct format_arg * e2) +{ + if (i < s->count) + { + const struct format_arg * e1 = &s->element[i]; + return (e1->repcount == e2->repcount && equal_element (e1, e2)); + } + return false; +} + +static bool +is_one_integer_less (const struct segment * s, unsigned int i, + const struct format_arg * e2) +{ + if (i < s->count) + { + const struct format_arg * e1 = &s->element[i]; + return (e1->repcount == e2->repcount - 1 + && equal_element (e1, e2)); + } + return false; +} + +/* Tests whether the first normalized argument list is equal to the + second one, or it omits at most one numeric or unspecified + argument. */ +/* Memory effects: none. */ +static bool +compatible_list (const struct format_arg_list *list1, + const struct format_arg_list *list2) +{ + unsigned int n, i1, i2; + bool already_skip = false; + + if (equal_list (list1, list2)) + return true; + + n = list2->initial.count; + if (n != list1->initial.count && n - 1 != list1->initial.count) + return false; + for (i1 = 0, i2 = 0; i2 < n; i1++, i2++) + { + const struct format_arg * e2 = &list2->initial.element[i2]; + if (!same_elements (&list1->initial, i1, e2)) + { + if (already_skip || e2->type != FAT_INTEGER) + return false; + + if (!is_one_integer_less (&list1->initial, i1, e2)) + --i1; + + already_skip = true; + } + } + + /* Not all elements have been parsed. */ + if (i1 != list1->initial.count || i2 != list2->initial.count) + return false; + + n = list2->repeated.count; + if (n != list2->repeated.count + && !(n - 1 == list1->initial.count && !already_skip)) + return false; + for (i1 = 0, i2 = 0; i2 < n; i1++, i2++) + { + const struct format_arg * e2 = &list2->repeated.element[i2]; + if (!same_elements (&list1->repeated, i1, e2)) + { + if (already_skip || e2->type != FAT_INTEGER) + return false; + + if (!is_one_integer_less (&list1->repeated, i1, e2)) + --i1; + + already_skip = true; + + } + } + + return (i1 == list1->repeated.count && i2 == list2->repeated.count); +} /* ===================== Incremental memory allocation ===================== */ @@ -3481,13 +3564,7 @@ format_check (void *msgid_descr, void *msgstr_descr, bool equality, } else { - struct format_arg_list *intersection = - make_intersected_list (copy_list (spec1->list), - copy_list (spec2->list)); - - if (!(intersection != NULL - && (normalize_list (intersection), - equal_list (intersection, spec2->list)))) + if (!compatible_list (spec2->list, spec1->list)) { if (error_logger) error_logger (_("format specifications in '%s' are not a subset of those in '%s'"), diff --git a/gettext-tools/src/format-scheme.c b/gettext-tools/src/format-scheme.c index 9958a475e..c2ad89ad3 100644 --- a/gettext-tools/src/format-scheme.c +++ b/gettext-tools/src/format-scheme.c @@ -335,6 +335,89 @@ equal_list (const struct format_arg_list *list1, return true; } +static bool +same_elements (const struct segment * s, unsigned int i, + const struct format_arg * e2) +{ + if (i < s->count) + { + const struct format_arg * e1 = &s->element[i]; + return (e1->repcount == e2->repcount && equal_element (e1, e2)); + } + return false; +} + +static bool +is_one_integer_less (const struct segment * s, unsigned int i, + const struct format_arg * e2) +{ + if (i < s->count) + { + const struct format_arg * e1 = &s->element[i]; + return (e1->repcount == e2->repcount - 1 + && equal_element (e1, e2)); + } + return false; +} + +/* Tests whether the first normalized argument list is equal to the + second one, or it omits at most one numeric or unspecified + argument. */ +/* Memory effects: none. */ +static bool +compatible_list (const struct format_arg_list *list1, + const struct format_arg_list *list2) +{ + unsigned int n, i1, i2; + bool already_skip = false; + + if (equal_list (list1, list2)) + return true; + + n = list2->initial.count; + if (n != list1->initial.count && n - 1 != list1->initial.count) + return false; + for (i1 = 0, i2 = 0; i2 < n; i1++, i2++) + { + const struct format_arg * e2 = &list2->initial.element[i2]; + if (!same_elements (&list1->initial, i1, e2)) + { + if (already_skip || e2->type != FAT_INTEGER) + return false; + + if (!is_one_integer_less (&list1->initial, i1, e2)) + --i1; + + already_skip = true; + } + } + + /* Not all elements have been parsed. */ + if (i1 != list1->initial.count || i2 != list2->initial.count) + return false; + + n = list2->repeated.count; + if (n != list2->repeated.count + && !(n - 1 == list1->initial.count && !already_skip)) + return false; + for (i1 = 0, i2 = 0; i2 < n; i1++, i2++) + { + const struct format_arg * e2 = &list2->repeated.element[i2]; + if (!same_elements (&list1->repeated, i1, e2)) + { + if (already_skip || e2->type != FAT_INTEGER) + return false; + + if (!is_one_integer_less (&list1->repeated, i1, e2)) + --i1; + + already_skip = true; + + } + } + + return (i1 == list1->repeated.count && i2 == list2->repeated.count); +} /* ===================== Incremental memory allocation ===================== */ @@ -3403,13 +3486,7 @@ format_check (void *msgid_descr, void *msgstr_descr, bool equality, } else { - struct format_arg_list *intersection = - make_intersected_list (copy_list (spec1->list), - copy_list (spec2->list)); - - if (!(intersection != NULL - && (normalize_list (intersection), - equal_list (intersection, spec2->list)))) + if (!compatible_list (spec2->list, spec1->list)) { if (error_logger) error_logger (_("format specifications in '%s' are not a subset of those in '%s'"), -- 2.29.2