diff options
author | Thomas Munro <tmunro@FreeBSD.org> | 2020-11-08 02:50:34 +0000 |
---|---|---|
committer | Thomas Munro <tmunro@FreeBSD.org> | 2020-11-08 02:50:34 +0000 |
commit | cc7edd258c2564fe9e3c4a0dc839acc4a71caff9 (patch) | |
tree | 713e7f140bcc509d153f6843f0c0c4e93cf43991 /lib/libc/locale | |
parent | d2799054f0d29c33a1f2ab87ee4d88970ec36d91 (diff) |
Add collation version support to querylocale(3).
Provide a way to ask for an opaque version string for a locale_t, so
that potential changes in sort order can be detected. Similar to
ICU's ucol_getVersion() and Windows' GetNLSVersionEx(), this API is
intended to allow databases to detect when text order-based indexes
might need to be rebuilt.
The CLDR version is extracted from CLDR source data by the Makefile
under tools/tools/locale, written into the machine-generated Makefile
under shared/colldef, passed to localedef -V, and then written into
LC_COLLATE file headers. The initial version is 34.0.
tools/tools/locale was recently updated to pull down 35.0, but the
output hasn't been committed under share/colldef yet, so that will
provide the first observable change when it happens. Other versioning
schemes are possible in future, because the format is unspecified.
Reviewed by: bapt, 0mp, kib, yuripv (albeit a long time ago)
Differential Revision: https://reviews.freebsd.org/D17166
Notes
Notes:
svn path=/head/; revision=367476
Diffstat (limited to 'lib/libc/locale')
-rw-r--r-- | lib/libc/locale/collate.c | 10 | ||||
-rw-r--r-- | lib/libc/locale/collate.h | 7 | ||||
-rw-r--r-- | lib/libc/locale/querylocale.3 | 32 | ||||
-rw-r--r-- | lib/libc/locale/xlocale.c | 19 | ||||
-rw-r--r-- | lib/libc/locale/xlocale_private.h | 5 |
5 files changed, 57 insertions, 16 deletions
diff --git a/lib/libc/locale/collate.c b/lib/libc/locale/collate.c index c67f7bcd646e..c992d2299ab7 100644 --- a/lib/libc/locale/collate.c +++ b/lib/libc/locale/collate.c @@ -140,7 +140,9 @@ __collate_load_tables_l(const char *encoding, struct xlocale_collate *table) (void) _close(fd); return (_LDP_ERROR); } - if (sbuf.st_size < (COLLATE_STR_LEN + sizeof (info))) { + if (sbuf.st_size < (COLLATE_FMT_VERSION_LEN + + XLOCALE_DEF_VERSION_LEN + + sizeof (info))) { (void) _close(fd); errno = EINVAL; return (_LDP_ERROR); @@ -151,12 +153,14 @@ __collate_load_tables_l(const char *encoding, struct xlocale_collate *table) return (_LDP_ERROR); } - if (strncmp(TMP, COLLATE_VERSION, COLLATE_STR_LEN) != 0) { + if (strncmp(TMP, COLLATE_FMT_VERSION, COLLATE_FMT_VERSION_LEN) != 0) { (void) munmap(map, sbuf.st_size); errno = EINVAL; return (_LDP_ERROR); } - TMP += COLLATE_STR_LEN; + TMP += COLLATE_FMT_VERSION_LEN; + strlcat(table->header.version, TMP, sizeof (table->header.version)); + TMP += XLOCALE_DEF_VERSION_LEN; info = (void *)TMP; TMP += sizeof (*info); diff --git a/lib/libc/locale/collate.h b/lib/libc/locale/collate.h index 4abb1f936ae2..9983cdbd969d 100644 --- a/lib/libc/locale/collate.h +++ b/lib/libc/locale/collate.h @@ -53,7 +53,9 @@ #endif #define COLLATE_STR_LEN 24 /* should be 64-bit multiple */ -#define COLLATE_VERSION "BSD 1.0\n" + +#define COLLATE_FMT_VERSION_LEN 12 +#define COLLATE_FMT_VERSION "BSD 1.0\n" #define COLLATE_MAX_PRIORITY (0x7fffffff) /* max signed value */ #define COLLATE_SUBST_PRIORITY (0x40000000) /* bit indicates subst table */ @@ -69,7 +71,8 @@ /* * The collate file format is as follows: * - * char version[COLLATE_STR_LEN]; // must be COLLATE_VERSION + * char fmt_version[COLLATE_FMT_VERSION_LEN]; // must be COLLATE_FMT_VERSION + * char def_version[XLOCALE_DEF_VERSION_LEN]; // NUL-terminated, may be empty * collate_info_t info; // see below, includes padding * collate_char_pri_t char_data[256]; // 8 bit char values * collate_subst_t subst[*]; // 0 or more substitutions diff --git a/lib/libc/locale/querylocale.3 b/lib/libc/locale/querylocale.3 index d1bb688ed907..ecafee49a712 100644 --- a/lib/libc/locale/querylocale.3 +++ b/lib/libc/locale/querylocale.3 @@ -27,12 +27,12 @@ .\" .\" $FreeBSD$ .\" -.Dd May 3, 2013 +.Dd November 8, 2020 .Dt QUERYLOCALE 3 .Os .Sh NAME .Nm querylocale -.Nd Look up the locale name for a specified category +.Nd Look up the locale name or version for a specified category .Sh LIBRARY .Lb libc .Sh SYNOPSIS @@ -40,11 +40,22 @@ .Ft const char * .Fn querylocale "int mask" "locale_t locale" .Sh DESCRIPTION -Returns the name of the locale for the category specified by +Returns the name or version of the locale for the category specified by .Fa mask . -This possible values for the mask are the same as those in -.Xr newlocale 3 . -If more than one bit in the mask is set, the returned value is undefined. +The possible values for the mask are the same as those in +.Xr newlocale 3 , +when requesting the locale name. +Specify the bitwise OR of +.Fa LC_VERSION_MASK +and another mask value to request a version string. +Version strings can be compared to detect changes to the locale's definition. +The structure of the version string is unspecified. +Currently, version information is only available for +.Fa LC_COLLATE_MASK , +and an empty string is returned for other categories. +If more than one bit in the mask is set, not counting +.Fa LC_VERSION_MASK , +the returned value is undefined. .Sh SEE ALSO .Xr duplocale 3 , .Xr freelocale 3 , @@ -52,3 +63,12 @@ If more than one bit in the mask is set, the returned value is undefined. .Xr newlocale 3 , .Xr uselocale 3 , .Xr xlocale 3 +.Sh HISTORY +The +.Fn querylocale +function first appeared in +.Fx 9.1 , +and is based on the function of the same name in Darwin. +.Fa LC_VERSION_MASK +first appeared in +.Fx 13.0 . diff --git a/lib/libc/locale/xlocale.c b/lib/libc/locale/xlocale.c index 465172fe24eb..fb674f86bbff 100644 --- a/lib/libc/locale/xlocale.c +++ b/lib/libc/locale/xlocale.c @@ -231,6 +231,8 @@ static int dupcomponent(int type, locale_t base, locale_t new) if (new->components[type]) { strncpy(new->components[type]->locale, src->locale, ENCODING_LEN); + strncpy(new->components[type]->version, src->version, + XLOCALE_DEF_VERSION_LEN); } } else if (base->components[type]) { new->components[type] = xlocale_retain(base->components[type]); @@ -346,17 +348,24 @@ freelocale(locale_t loc) } /* - * Returns the name of the locale for a particular component of a locale_t. + * Returns the name or version of the locale for a particular component of a + * locale_t. */ const char *querylocale(int mask, locale_t loc) { - int type = ffs(mask) - 1; + int type = ffs(mask & ~LC_VERSION_MASK) - 1; FIX_LOCALE(loc); if (type >= XLC_LAST) return (NULL); - if (loc->components[type]) - return (loc->components[type]->locale); - return ("C"); + if (mask & LC_VERSION_MASK) { + if (loc->components[type]) + return (loc->components[type]->version); + return (""); + } else { + if (loc->components[type]) + return (loc->components[type]->locale); + return ("C"); + } } /* diff --git a/lib/libc/locale/xlocale_private.h b/lib/libc/locale/xlocale_private.h index fc04c9dd43a3..391e375bc03d 100644 --- a/lib/libc/locale/xlocale_private.h +++ b/lib/libc/locale/xlocale_private.h @@ -91,6 +91,9 @@ struct xlocale_refcounted { /** Function used to destroy this component, if one is required*/ void(*destructor)(void*); }; + +#define XLOCALE_DEF_VERSION_LEN 12 + /** * Header for a locale component. All locale components must begin with this * header. @@ -99,6 +102,8 @@ struct xlocale_component { struct xlocale_refcounted header; /** Name of the locale used for this component. */ char locale[ENCODING_LEN+1]; + /** Version of the definition for this component. */ + char version[XLOCALE_DEF_VERSION_LEN]; }; /** |