>From 453daea3e96c7bcbea4c665c83988eb58f41b1dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20=C3=81ngel=20Arruga=20Vivas?= Date: Fri, 27 Nov 2020 14:49:23 +0100 Subject: [PATCH 2/2] format-lisp, format-scheme: Add subset comparison functions. * gettext-tools/src/format-lisp.c (subset_list): New function. (element_comparator, length_comparator): New types. (equal_list): Refactored its code into ... (equal_length, compare_segments, compare_list): ... these functions. (subset_element, subset_list, subset_length): New functions. (format_check): Use subset_list when equality is false. * gettext-tools/src/format-scheme.c (subset_list): New function. (element_comparator, length_comparator): New types. (equal_list): Refactored its code into ... (equal_length, compare_segments, compare_list): ... these functions. (subset_element, subset_list, subset_length): New functions. (format_check): Use subset_list when equality is false. --- gettext-tools/src/format-lisp.c | 123 ++++++++++++++++++++++------- gettext-tools/src/format-scheme.c | 126 +++++++++++++++++++++++------- 2 files changed, 189 insertions(+), 60 deletions(-) diff --git a/gettext-tools/src/format-lisp.c b/gettext-tools/src/format-lisp.c index 94194dbef..48af41afc 100644 --- a/gettext-tools/src/format-lisp.c +++ b/gettext-tools/src/format-lisp.c @@ -134,6 +134,8 @@ static void free_list (struct format_arg_list *list); static struct format_arg_list * copy_list (const struct format_arg_list *list); static bool equal_list (const struct format_arg_list *list1, const struct format_arg_list *list2); +static bool subset_list (const struct format_arg_list *left, + const struct format_arg_list *right); static struct format_arg_list * make_intersected_list (struct format_arg_list *list1, struct format_arg_list *list2); @@ -285,6 +287,12 @@ copy_list (const struct format_arg_list *list) /* ===================== Compare two format_arg_lists ===================== */ +typedef bool (*element_comparator) (const struct format_arg *, + const struct format_arg *); + +typedef bool (*length_comparator) (const struct segment *, + const struct segment *); + /* Tests whether two normalized argument constraints are equivalent, ignoring the repcount. */ static bool @@ -295,44 +303,105 @@ equal_element (const struct format_arg * e1, const struct format_arg * e2) && (e1->type == FAT_LIST ? equal_list (e1->list, e2->list) : true)); } -/* Tests whether two normalized argument list constraints are equivalent. */ -/* Memory effects: none. */ static bool -equal_list (const struct format_arg_list *list1, - const struct format_arg_list *list2) +equal_length (const struct segment *s1, const struct segment *s2) { - unsigned int n, i; + return (s1->count == s2->count); +} - VERIFY_LIST (list1); - VERIFY_LIST (list2); +/* Tests whether two segments are accepted by the provided comparison + predicate. */ +static bool +compare_segments (const struct segment *s1, const struct segment *s2, + element_comparator compare_element, + length_comparator compare_length) +{ + unsigned int i; - n = list1->initial.count; - if (n != list2->initial.count) + if (!compare_length (s1, s2)) return false; - for (i = 0; i < n; i++) + for (i = 0; i < s1->count; i++) { - const struct format_arg * e1 = &list1->initial.element[i]; - const struct format_arg * e2 = &list2->initial.element[i]; + const struct format_arg * e1 = &s1->element[i]; + const struct format_arg * e2 = &s2->element[i]; - if (!(e1->repcount == e2->repcount && equal_element (e1, e2))) + if (!(e1->repcount == e2->repcount && compare_element (e1, e2))) return false; } - n = list1->repeated.count; - if (n != list2->repeated.count) - return false; - for (i = 0; i < n; i++) - { - const struct format_arg * e1 = &list1->repeated.element[i]; - const struct format_arg * e2 = &list2->repeated.element[i]; + return true; +} - if (!(e1->repcount == e2->repcount && equal_element (e1, e2))) - return false; +/* Tests whether two normalized argument constraints are accepted by + the provided comparison predicate. */ +static bool +compare_list (const struct format_arg_list *list1, + const struct format_arg_list *list2, + element_comparator c, length_comparator l) +{ + VERIFY_LIST (list1); + VERIFY_LIST (list2); + + return (compare_segments (&list1->initial, &list2->initial, c, l) + && compare_segments (&list1->repeated, &list2->repeated, c, l)); +} + +/* Tests whether two normalized argument list constraints are equivalent. */ +/* Memory effects: none. */ +static bool +equal_list (const struct format_arg_list *list1, + const struct format_arg_list *list2) +{ + return compare_list (list1, list2, &equal_element, &equal_length); +} + +/* Tests whether the normalized argument constraints have a subset + relationship, ignoring the repcount. */ +static bool +subset_element (const struct format_arg * left, const struct format_arg * right) +{ + if (equal_element (left, right)) + return true; + + if (left->presence == right->presence) + { + switch (left->type) + { + case FAT_LIST: + return (right->type == FAT_LIST && subset_list (left->list, + right->list)); + /* Allow wider types in addition to equality. */ + case FAT_OBJECT: + return true; + case FAT_CHARACTER_INTEGER_NULL: + return (right->type == FAT_CHARACTER_NULL + || right->type == FAT_INTEGER_NULL); + case FAT_CHARACTER_NULL: + return right->type == FAT_CHARACTER; + case FAT_INTEGER_NULL: + case FAT_REAL: + return right->type == FAT_INTEGER; + } } - return true; + /* The left hand isn't compatible with the right hand type. */ + return false; } +static bool +subset_length (const struct segment *s1, const struct segment *s2) +{ + return (s1->count <= s2->count); +} + +/* Tests whether the left argument constraints are a subset of the + constraints provided by the right argument. */ +static bool +subset_list (const struct format_arg_list *left, + const struct format_arg_list *right) +{ + return compare_list (left, right, &subset_element, &subset_length); +} /* ===================== Incremental memory allocation ===================== */ @@ -3481,13 +3550,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 (!subset_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..0b0641c79 100644 --- a/gettext-tools/src/format-scheme.c +++ b/gettext-tools/src/format-scheme.c @@ -136,6 +136,8 @@ static void free_list (struct format_arg_list *list); static struct format_arg_list * copy_list (const struct format_arg_list *list); static bool equal_list (const struct format_arg_list *list1, const struct format_arg_list *list2); +static bool subset_list (const struct format_arg_list *left, + const struct format_arg_list *right); static struct format_arg_list * make_intersected_list (struct format_arg_list *list1, struct format_arg_list *list2); @@ -287,6 +289,12 @@ copy_list (const struct format_arg_list *list) /* ===================== Compare two format_arg_lists ===================== */ +typedef bool (*element_comparator) (const struct format_arg *, + const struct format_arg *); + +typedef bool (*length_comparator) (const struct segment *, + const struct segment *); + /* Tests whether two normalized argument constraints are equivalent, ignoring the repcount. */ static bool @@ -297,44 +305,108 @@ equal_element (const struct format_arg * e1, const struct format_arg * e2) && (e1->type == FAT_LIST ? equal_list (e1->list, e2->list) : true)); } -/* Tests whether two normalized argument list constraints are equivalent. */ -/* Memory effects: none. */ static bool -equal_list (const struct format_arg_list *list1, - const struct format_arg_list *list2) +equal_length (const struct segment *s1, const struct segment *s2) { - unsigned int n, i; + return (s1->count == s2->count); +} - VERIFY_LIST (list1); - VERIFY_LIST (list2); +/* Tests whether two segments are accepted by the provided comparison + predicate. */ +static bool +compare_segments (const struct segment *s1, const struct segment *s2, + element_comparator compare_element, + length_comparator compare_length) +{ + unsigned int i; - n = list1->initial.count; - if (n != list2->initial.count) + if (!compare_length (s1, s2)) return false; - for (i = 0; i < n; i++) + for (i = 0; i < s1->count; i++) { - const struct format_arg * e1 = &list1->initial.element[i]; - const struct format_arg * e2 = &list2->initial.element[i]; + const struct format_arg * e1 = &s1->element[i]; + const struct format_arg * e2 = &s2->element[i]; - if (!(e1->repcount == e2->repcount && equal_element (e1, e2))) + if (!(e1->repcount == e2->repcount && compare_element (e1, e2))) return false; } - n = list1->repeated.count; - if (n != list2->repeated.count) - return false; - for (i = 0; i < n; i++) - { - const struct format_arg * e1 = &list1->repeated.element[i]; - const struct format_arg * e2 = &list2->repeated.element[i]; + return true; +} - if (!(e1->repcount == e2->repcount && equal_element (e1, e2))) - return false; +/* Tests whether two normalized argument constraints are accepted by + the provided comparison predicate. */ +static bool +compare_list (const struct format_arg_list *list1, + const struct format_arg_list *list2, + element_comparator e, length_comparator l) +{ + VERIFY_LIST (list1); + VERIFY_LIST (list2); + + return (compare_segments (&list1->initial, &list2->initial, e, l) + && compare_segments (&list1->repeated, &list2->repeated, e, l)); +} + +/* Tests whether two normalized argument list constraints are equivalent. */ +/* Memory effects: none. */ +static bool +equal_list (const struct format_arg_list *list1, + const struct format_arg_list *list2) +{ + return compare_list (list1, list2, &equal_element, &equal_length); +} + +/* Tests whether the normalized argument constraints have a subset + relationship, ignoring the repcount. */ +static bool +subset_element (const struct format_arg * left, const struct format_arg * right) +{ + if (equal_element (left, right)) + return true; + + if (left->presence == right->presence) + { + switch (left->type) + { + case FAT_LIST: + return (right->type == FAT_LIST && subset_list (left->list, + right->list)); + /* Allow wider types in addition to equality. */ + case FAT_OBJECT: + return true; + case FAT_CHARACTER_INTEGER_NULL: + return (right->type == FAT_CHARACTER_NULL + || right->type == FAT_INTEGER_NULL); + case FAT_CHARACTER_NULL: + return right->type == FAT_CHARACTER; + case FAT_INTEGER_NULL: + return right->type == FAT_INTEGER; + case FAT_REAL: + return right->type == FAT_INTEGER; + case FAT_COMPLEX: + return (right->type == FAT_REAL || right->type == FAT_INTEGER); + } } - return true; + /* The left hand isn't compatible with the right hand type. */ + return false; } +static bool +subset_length (const struct segment *s1, const struct segment *s2) +{ + return (s1->count <= s2->count); +} + +/* Tests whether the left argument constraints are a subset of the + constraints provided by the right argument. */ +static bool +subset_list (const struct format_arg_list *left, + const struct format_arg_list *right) +{ + return compare_list (left, right, &subset_element, &subset_length); +} /* ===================== Incremental memory allocation ===================== */ @@ -3403,13 +3475,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 (!subset_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