diff options
author | Carlos O'Donell <carlos@redhat.com> | 2021-07-29 22:45:39 -0400 |
---|---|---|
committer | Carlos O'Donell <carlos@redhat.com> | 2021-09-06 11:06:45 -0400 |
commit | f5117c6504888fab5423282a4607c552b90fd3f9 (patch) | |
tree | 2961802e4e55a5669f9b224923955871524a33fd /locale/programs/ld-collate.c | |
parent | 1d9f99ce1b3788d1897cb53a76d57e973111b8fe (diff) | |
download | glibc-f5117c6504888fab5423282a4607c552b90fd3f9.tar.gz glibc-f5117c6504888fab5423282a4607c552b90fd3f9.tar.xz glibc-f5117c6504888fab5423282a4607c552b90fd3f9.zip |
Add 'codepoint_collation' support for LC_COLLATE.
Support a new directive 'codepoint_collation' in the LC_COLLATE section of a locale source file. This new directive causes all collation rules to be dropped and instead STRCMP (strcmp or wcscmp) is used for collation of the input character set. This is required to allow for a C.UTF-8 that contains zero collation rules (minimal size) and sorts using code point sorting. To date the only implementation of a locale with zero collation rules is the C/POSIX locale. The C/POSIX locale provides identity tables for _NL_COLLATE_COLLSEQMB and _NL_COLLATE_COLLSEQWC that map to ASCII even though it has zero rules. This has lead to existing fnmatch, regexec, and regcomp implementations that require these tables. It is not correct to use these tables when nrules == 0, but the conservative fix is to provide these tables when nrules == 0. This assures that existing static applications using a new C.UTF-8 locale with 'codepoint_collation' at least have functional range expressions with ASCII e.g. [0-9] or [a-z]. Such static applications would not have the fixes to fnmatch, regexec and regcomp that avoid the use of the tables when nrules == 0. Future fixes to fnmatch, regexec, and regcomp would allow range expressions to use the full set of code points for such ranges. Tested on x86_64 and i686 without regression. Reviewed-by: Florian Weimer <fweimer@redhat.com>
Diffstat (limited to 'locale/programs/ld-collate.c')
-rw-r--r-- | locale/programs/ld-collate.c | 36 |
1 files changed, 33 insertions, 3 deletions
diff --git a/locale/programs/ld-collate.c b/locale/programs/ld-collate.c index f4a8f34e46..06a5203334 100644 --- a/locale/programs/ld-collate.c +++ b/locale/programs/ld-collate.c @@ -23,6 +23,7 @@ #include <wchar.h> #include <stdint.h> #include <sys/param.h> +#include <array_length.h> #include "localedef.h" #include "charmap.h" @@ -194,6 +195,9 @@ struct name_list /* The real definition of the struct for the LC_COLLATE locale. */ struct locale_collate_t { + /* Does the locale use code points to compare the encoding? */ + bool codepoint_collation; + int col_weight_max; int cur_weight_max; @@ -1509,6 +1513,7 @@ collate_startup (struct linereader *ldfile, struct localedef_t *locale, obstack_init (&collate->mempool); collate->col_weight_max = -1; + collate->codepoint_collation = false; } else /* Reuse the copy_locale's data structures. */ @@ -1567,6 +1572,10 @@ collate_finish (struct localedef_t *locale, const struct charmap_t *charmap) return; } + /* No data required. */ + if (collate->codepoint_collation) + return; + /* If this assertion is hit change the type in `element_t'. */ assert (nrules <= sizeof (runp->used_in_level) * 8); @@ -2091,6 +2100,10 @@ add_to_tablewc (uint32_t ch, struct element_t *runp) } } +/* Include the C locale identity tables for _NL_COLLATE_COLLSEQMB and + _NL_COLLATE_COLLSEQWC. */ +#include "C-collate-seq.c" + void collate_output (struct localedef_t *locale, const struct charmap_t *charmap, const char *output_path) @@ -2114,7 +2127,7 @@ collate_output (struct localedef_t *locale, const struct charmap_t *charmap, add_locale_uint32 (&file, nrules); /* If we have no LC_COLLATE data emit only the number of rules as zero. */ - if (collate == NULL) + if (collate == NULL || collate->codepoint_collation) { size_t idx; for (idx = 1; idx < nelems; idx++) @@ -2122,6 +2135,17 @@ collate_output (struct localedef_t *locale, const struct charmap_t *charmap, /* The words have to be handled specially. */ if (idx == _NL_ITEM_INDEX (_NL_COLLATE_SYMB_HASH_SIZEMB)) add_locale_uint32 (&file, 0); + else if (idx == _NL_ITEM_INDEX (_NL_COLLATE_CODESET) + && collate != NULL) + /* A valid LC_COLLATE must have a code set name. */ + add_locale_string (&file, charmap->code_set_name); + else if (idx == _NL_ITEM_INDEX (_NL_COLLATE_COLLSEQMB) + && collate != NULL) + add_locale_raw_data (&file, collseqmb, sizeof (collseqmb)); + else if (idx == _NL_ITEM_INDEX (_NL_COLLATE_COLLSEQWC) + && collate != NULL) + add_locale_uint32_array (&file, collseqwc, + array_length (collseqwc)); else add_locale_empty (&file); } @@ -2671,6 +2695,10 @@ collate_read (struct linereader *ldfile, struct localedef_t *result, switch (nowtok) { + case tok_codepoint_collation: + collate->codepoint_collation = true; + break; + case tok_copy: /* Allow copying other locales. */ now = lr_token (ldfile, charmap, result, NULL, verbose); @@ -3741,9 +3769,11 @@ error while adding equivalent collating symbol")); /* Next we assume `LC_COLLATE'. */ if (!ignore_content) { - if (state == 0 && copy_locale == NULL) + if (state == 0 + && copy_locale == NULL + && !collate->codepoint_collation) /* We must either see a copy statement or have - ordering values. */ + ordering values, or codepoint_collation. */ lr_error (ldfile, _("%s: empty category description not allowed"), "LC_COLLATE"); |