Module Name:    src
Committed By:   joerg
Date:           Sat Jun  8 21:35:18 UTC 2024

Modified Files:
        src/lib/libc/locale: global_locale.c setlocale.c setlocale_local.h
        src/lib/libc/string: Makefile.inc strerror_r.c

Log Message:
Redo l10n support in the strerror family.

Instead of opening the message catelog whenever strerror is called,
keep track of the translations in the locale cache. For the C locale,
the builtin sys_errlist is used directly. Other locales will open
the catalog file on the first strerror call and build a translation
table, so that further calls in this locale can just use an array
lookup.


To generate a diff of this commit:
cvs rdiff -u -r1.28 -r1.29 src/lib/libc/locale/global_locale.c
cvs rdiff -u -r1.65 -r1.66 src/lib/libc/locale/setlocale.c
cvs rdiff -u -r1.17 -r1.18 src/lib/libc/locale/setlocale_local.h
cvs rdiff -u -r1.89 -r1.90 src/lib/libc/string/Makefile.inc
cvs rdiff -u -r1.5 -r1.6 src/lib/libc/string/strerror_r.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/lib/libc/locale/global_locale.c
diff -u src/lib/libc/locale/global_locale.c:1.28 src/lib/libc/locale/global_locale.c:1.29
--- src/lib/libc/locale/global_locale.c:1.28	Fri Jun  7 13:53:23 2024
+++ src/lib/libc/locale/global_locale.c	Sat Jun  8 21:35:18 2024
@@ -1,4 +1,4 @@
-/* $NetBSD: global_locale.c,v 1.28 2024/06/07 13:53:23 riastradh Exp $ */
+/* $NetBSD: global_locale.c,v 1.29 2024/06/08 21:35:18 joerg Exp $ */
 
 /*-
  * Copyright (c)2008 Citrus Project,
@@ -28,12 +28,15 @@
 
 #include <sys/cdefs.h>
 #if defined(LIBC_SCCS) && !defined(lint)
-__RCSID("$NetBSD: global_locale.c,v 1.28 2024/06/07 13:53:23 riastradh Exp $");
+__RCSID("$NetBSD: global_locale.c,v 1.29 2024/06/08 21:35:18 joerg Exp $");
 #endif /* LIBC_SCCS and not lint */
 
+#include "namespace.h"
+
 #include <sys/types.h>
 #include <sys/ctype_bits.h>
 #include <sys/localedef.h>
+#include <errno.h>
 #include <langinfo.h>
 #include <limits.h>
 #define __SETLOCALE_SOURCE__
@@ -137,6 +140,9 @@ __dso_hidden const struct _locale_cache_
     },
     .monetary_name = _lc_C_locale_name,
     .numeric_name = _lc_C_locale_name,
+    .message_name = _lc_C_locale_name,
+    .errlistp = &sys_errlist,
+    .errlist_prefix = "Unknown error: %d",
 };
 
 struct _locale _lc_global_locale = {

Index: src/lib/libc/locale/setlocale.c
diff -u src/lib/libc/locale/setlocale.c:1.65 src/lib/libc/locale/setlocale.c:1.66
--- src/lib/libc/locale/setlocale.c:1.65	Thu Jan  4 20:57:29 2018
+++ src/lib/libc/locale/setlocale.c	Sat Jun  8 21:35:18 2024
@@ -1,4 +1,4 @@
-/* $NetBSD: setlocale.c,v 1.65 2018/01/04 20:57:29 kamil Exp $ */
+/* $NetBSD: setlocale.c,v 1.66 2024/06/08 21:35:18 joerg Exp $ */
 
 /*-
  * Copyright (c)2008 Citrus Project,
@@ -28,7 +28,7 @@
 
 #include <sys/cdefs.h>
 #if defined(LIBC_SCCS) && !defined(lint)
-__RCSID("$NetBSD: setlocale.c,v 1.65 2018/01/04 20:57:29 kamil Exp $");
+__RCSID("$NetBSD: setlocale.c,v 1.66 2024/06/08 21:35:18 joerg Exp $");
 #endif /* LIBC_SCCS and not lint */
 
 #include "namespace.h"
@@ -65,6 +65,7 @@ _setlocale_cache(locale_t loc, struct _l
 {
 	const char *monetary_name = loc->part_name[LC_MONETARY];
 	const char *numeric_name = loc->part_name[LC_NUMERIC];
+	const char *message_name = loc->part_name[LC_MESSAGES];
 	_NumericLocale *numeric = loc->part_impl[LC_NUMERIC];
 	_MonetaryLocale *monetary = loc->part_impl[LC_MONETARY];
 	struct lconv *ldata;
@@ -78,6 +79,9 @@ _setlocale_cache(locale_t loc, struct _l
 		if (numeric_name != old_cache->numeric_name &&
 		    strcmp(numeric_name, old_cache->numeric_name) != 0)
 			continue;
+		if (message_name != old_cache->message_name &&
+		    strcmp(message_name, old_cache->message_name) != 0)
+			continue;
 		loc->cache = old_cache;
 		free(cache);
 		return 0;
@@ -91,6 +95,10 @@ _setlocale_cache(locale_t loc, struct _l
 
 	cache->monetary_name = monetary_name;
 	cache->numeric_name = numeric_name;
+	cache->message_name = message_name;
+	cache->errlist = NULL;
+	cache->errlistp = &cache->errlist;
+	cache->errlist_prefix = NULL;
 	ldata = &cache->ldata;
 
 	ldata->decimal_point = __UNCONST(numeric->decimal_point);

Index: src/lib/libc/locale/setlocale_local.h
diff -u src/lib/libc/locale/setlocale_local.h:1.17 src/lib/libc/locale/setlocale_local.h:1.18
--- src/lib/libc/locale/setlocale_local.h:1.17	Fri Apr 29 16:26:48 2016
+++ src/lib/libc/locale/setlocale_local.h	Sat Jun  8 21:35:18 2024
@@ -1,4 +1,4 @@
-/* $NetBSD: setlocale_local.h,v 1.17 2016/04/29 16:26:48 joerg Exp $ */
+/* $NetBSD: setlocale_local.h,v 1.18 2024/06/08 21:35:18 joerg Exp $ */
 
 /*-
  * Copyright (c)2008 Citrus Project,
@@ -48,7 +48,11 @@ struct _locale_cache_t {
 	SLIST_ENTRY(_locale_cache_t) cache_link;
 	const char *monetary_name;
 	const char *numeric_name;
+	const char *message_name;
 	struct lconv ldata;
+	const char * errlist_prefix;
+	const char * const *errlist;
+	const char * const **errlistp;
 };
 
 struct _locale {

Index: src/lib/libc/string/Makefile.inc
diff -u src/lib/libc/string/Makefile.inc:1.89 src/lib/libc/string/Makefile.inc:1.90
--- src/lib/libc/string/Makefile.inc:1.89	Fri Aug 11 13:07:17 2023
+++ src/lib/libc/string/Makefile.inc	Sat Jun  8 21:35:18 2024
@@ -1,5 +1,5 @@
 #	from: @(#)Makefile.inc	8.1 (Berkeley) 6/4/93
-#	$NetBSD: Makefile.inc,v 1.89 2023/08/11 13:07:17 ryoon Exp $
+#	$NetBSD: Makefile.inc,v 1.90 2024/06/08 21:35:18 joerg Exp $
 
 # string sources
 .PATH: ${ARCHDIR}/string ${.CURDIR}/string
@@ -40,6 +40,8 @@ CPPFLAGS.wmemcmp.c+=	-I${LIBCDIR}/locale
 # to recurse and blow the stack.
 COPTS.memset.c+=	${${ACTIVE_CC} == "gcc":? -fno-builtin :}
 
+COPTS.strerror_r.c+= 	-Wno-format-nonliteral
+
 .include "${ARCHDIR}/string/Makefile.inc"
 
 MAN+=	bm.3 bcmp.3 bcopy.3 bstring.3 bzero.3 consttime_memequal.3 \

Index: src/lib/libc/string/strerror_r.c
diff -u src/lib/libc/string/strerror_r.c:1.5 src/lib/libc/string/strerror_r.c:1.6
--- src/lib/libc/string/strerror_r.c:1.5	Wed Mar 25 16:15:41 2020
+++ src/lib/libc/string/strerror_r.c	Sat Jun  8 21:35:18 2024
@@ -1,4 +1,4 @@
-/*	$NetBSD: strerror_r.c,v 1.5 2020/03/25 16:15:41 kre Exp $	*/
+/*	$NetBSD: strerror_r.c,v 1.6 2024/06/08 21:35:18 joerg Exp $	*/
 
 /*
  * Copyright (c) 1988 Regents of the University of California.
@@ -30,12 +30,14 @@
  */
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: strerror_r.c,v 1.5 2020/03/25 16:15:41 kre Exp $");
+__RCSID("$NetBSD: strerror_r.c,v 1.6 2024/06/08 21:35:18 joerg Exp $");
 
 #include "namespace.h"
 #include <assert.h>
+#include <atomic.h>
 #include <errno.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 #include <stdio.h>	/* for sys_nerr on FreeBSD */
 #ifdef NLS
@@ -48,33 +50,97 @@ __RCSID("$NetBSD: strerror_r.c,v 1.5 202
 
 #include "extern.h"
 
+#define	UPREFIX	"Unknown error: %d"
+
 __weak_alias(strerror_r, _strerror_r)
 
+#ifdef NLS
+static void
+load_errlist(locale_t loc)
+{
+	const char **errlist;
+	char *errlist_prefix;
+	int i;
+	nl_catd catd;
+	catd = catopen_l("libc", NL_CAT_LOCALE, loc);
+
+	if (loc->cache->errlist_prefix == NULL) {
+		errlist_prefix = strdup(catgets(catd, 1, 0xffff, UPREFIX));
+		if (errlist_prefix == NULL)
+			goto cleanup2;
+
+		membar_release();
+		if (atomic_cas_ptr(__UNCONST(&loc->cache->errlist_prefix),
+				   NULL, errlist_prefix) != NULL)
+			free(errlist_prefix);
+	}
+
+	if (loc->cache->errlist)
+		goto cleanup2;
+
+	errlist = calloc(sys_nerr, sizeof(*errlist));
+	if (errlist == NULL)
+		goto cleanup2;
+	for (i = 0; i < sys_nerr; ++i) {
+		errlist[i] = strdup(catgets(catd, 1, i, sys_errlist[i]));
+		if (errlist[i] == NULL)
+			goto cleanup;
+	}
+	membar_release();
+	if (atomic_cas_ptr(__UNCONST(&loc->cache->errlist), NULL, errlist) != NULL)
+		goto cleanup;
+	goto cleanup2;
+
+  cleanup:
+	for (i = 0; i < sys_nerr; ++i)
+		free(__UNCONST(errlist[i]));
+	free(errlist);
+  cleanup2:
+	catclose(catd);
+}
+#endif
+
 int
 _strerror_lr(int num, char *buf, size_t buflen, locale_t loc)
 {
-#define	UPREFIX	"Unknown error: %d"
 	unsigned int errnum = num;
 	int retval = 0;
 	size_t slen;
 	int saved_errno = errno;
 #ifdef NLS
-	nl_catd catd;
-	catd = catopen_l("libc", NL_CAT_LOCALE, loc);
+	const char * const *errlist;
+	const char *errlist_prefix;
 #endif
+
 	_DIAGASSERT(buf != NULL);
 
 	if (errnum < (unsigned int) sys_nerr) {
 #ifdef NLS
-		slen = strlcpy(buf, catgets(catd, 1, num,
-		    sys_errlist[errnum]), buflen); 
+		errlist = *loc->cache->errlistp;
+		membar_datadep_consumer();
+		if (errlist == NULL) {
+			load_errlist(loc);
+			errlist = *loc->cache->errlistp;
+			membar_datadep_consumer();
+			if (errlist == NULL)
+				errlist = *LC_C_LOCALE->cache->errlistp;
+		}
+		slen = strlcpy(buf, errlist[errnum], buflen);
 #else
-		slen = strlcpy(buf, sys_errlist[errnum], buflen); 
+		slen = strlcpy(buf, sys_errlist[errnum], buflen);
 #endif
 	} else {
 #ifdef NLS
-		slen = snprintf_l(buf, buflen, loc,
-		    catgets(catd, 1, 0xffff, UPREFIX), num);
+		errlist_prefix = loc->cache->errlist_prefix;
+		membar_datadep_consumer();
+		if (errlist_prefix == NULL) {
+			load_errlist(loc);
+			errlist_prefix = loc->cache->errlist_prefix;
+			membar_datadep_consumer();
+			if (errlist_prefix == NULL)
+				errlist_prefix = LC_C_LOCALE->cache->errlist_prefix;
+		}
+		slen = snprintf_l(buf, buflen, loc, errlist_prefix, num);
 #else
 		slen = snprintf(buf, buflen, UPREFIX, num);
 #endif
@@ -84,9 +150,6 @@ _strerror_lr(int num, char *buf, size_t 
 	if (slen >= buflen)
 		retval = ERANGE;
 
-#ifdef NLS
-	catclose(catd);
-#endif
 	errno = saved_errno;
 
 	return retval;

Reply via email to