aboutsummaryrefslogtreecommitdiff
path: root/lib/libc/locale
diff options
context:
space:
mode:
authorThomas Munro <tmunro@FreeBSD.org>2020-11-08 02:50:34 +0000
committerThomas Munro <tmunro@FreeBSD.org>2020-11-08 02:50:34 +0000
commitcc7edd258c2564fe9e3c4a0dc839acc4a71caff9 (patch)
tree713e7f140bcc509d153f6843f0c0c4e93cf43991 /lib/libc/locale
parentd2799054f0d29c33a1f2ab87ee4d88970ec36d91 (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.c10
-rw-r--r--lib/libc/locale/collate.h7
-rw-r--r--lib/libc/locale/querylocale.332
-rw-r--r--lib/libc/locale/xlocale.c19
-rw-r--r--lib/libc/locale/xlocale_private.h5
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];
};
/**