git: c1f46b8fcb97 - main - libc: iconv: push option ignore into citrus_iconv_open()

From: Kyle Evans <kevans_at_FreeBSD.org>
Date: Thu, 11 Aug 2022 16:43:47 UTC
The branch main has been updated by kevans:

URL: https://cgit.FreeBSD.org/src/commit/?id=c1f46b8fcb9758b52afce5971d12167628f62dfd

commit c1f46b8fcb9758b52afce5971d12167628f62dfd
Author:     Kyle Evans <kevans@FreeBSD.org>
AuthorDate: 2022-02-22 07:10:05 +0000
Commit:     Kyle Evans <kevans@FreeBSD.org>
CommitDate: 2022-08-11 16:33:28 +0000

    libc: iconv: push option ignore into citrus_iconv_open()
    
    Make it vaguely aware of options in the sense that it now knows that it
    can zap any trailing //.  It now copies the entire string in realsrc and
    realdst, then terminates them at the options.
    
    __bsd___iconv_open can now stop trying to allocate memory just for this
    purpose, and the new version is technically more correct.  GNU libiconv
    will ignore options on the `in` codeset and still do the right thing.
    
    Sponsored by:   Klara, Inc.
    Differential Revision:  https://reviews.freebsd.org/D34343
---
 lib/libc/iconv/bsd_iconv.c    | 16 +---------------
 lib/libc/iconv/citrus_iconv.c | 28 +++++++++++++++++++++-------
 2 files changed, 22 insertions(+), 22 deletions(-)

diff --git a/lib/libc/iconv/bsd_iconv.c b/lib/libc/iconv/bsd_iconv.c
index 0fcff0e2d1b8..5a0f523b9d15 100644
--- a/lib/libc/iconv/bsd_iconv.c
+++ b/lib/libc/iconv/bsd_iconv.c
@@ -56,8 +56,6 @@
 static iconv_t
 __bsd___iconv_open(const char *out, const char *in, struct _citrus_iconv *handle)
 {
-	const char *out_slashes;
-	char *out_noslashes;
 	int ret;
 
 	/*
@@ -66,19 +64,7 @@ __bsd___iconv_open(const char *out, const char *in, struct _citrus_iconv *handle
 	 * This is for compatibility with software that uses these
 	 * blindly.
 	 */
-	out_slashes = strstr(out, "//");
-	if (out_slashes != NULL) {
-		out_noslashes = strndup(out, out_slashes - out);
-		if (out_noslashes == NULL) {
-			errno = ENOMEM;
-			return ((iconv_t)-1);
-		}
-		ret = _citrus_iconv_open(&handle, in, out_noslashes);
-		free(out_noslashes);
-	} else {
-		ret = _citrus_iconv_open(&handle, in, out);
-	}
-
+	ret = _citrus_iconv_open(&handle, in, out);
 	if (ret) {
 		errno = ret == ENOENT ? EINVAL : ret;
 		return ((iconv_t)-1);
diff --git a/lib/libc/iconv/citrus_iconv.c b/lib/libc/iconv/citrus_iconv.c
index fbabf6524399..88dfc2deca33 100644
--- a/lib/libc/iconv/citrus_iconv.c
+++ b/lib/libc/iconv/citrus_iconv.c
@@ -126,7 +126,12 @@ open_shared(struct _citrus_iconv_shared * __restrict * __restrict rci,
 	 * See gettext-0.18.3+ NEWS:
 	 *   msgfmt now checks PO file headers more strictly with less
 	 *   false-positives.
-	 * NetBSD don't do this either.
+	 * NetBSD, also, doesn't do the below pass-through.
+	 *
+	 * Also note that this currently falls short if dst options have been
+	 * specified. It may be the case that we want to ignore EILSEQ, in which
+	 * case we should also select iconv_std anyways.  This trick, while
+	 * clever, may not be worth it.
 	 */
 	module = (strcmp(src, dst) != 0) ? "iconv_std" : "iconv_none";
 #else
@@ -279,7 +284,7 @@ _citrus_iconv_open(struct _citrus_iconv * __restrict * __restrict rcv,
 {
 	struct _citrus_iconv *cv = NULL;
 	struct _citrus_iconv_shared *ci = NULL;
-	char realdst[PATH_MAX], realsrc[PATH_MAX];
+	char realdst[PATH_MAX], realsrc[PATH_MAX], *slashes;
 #ifdef _PATH_ICONV
 	char buf[PATH_MAX], path[PATH_MAX];
 #endif
@@ -293,16 +298,25 @@ _citrus_iconv_open(struct _citrus_iconv * __restrict * __restrict rcv,
 	if ((strcmp(dst, "") == 0) || (strcmp(dst, "char") == 0))
 		dst = nl_langinfo(CODESET);
 
+	strlcpy(realsrc, src, (size_t)PATH_MAX);
+	if ((slashes = strstr(realsrc, "//")) != NULL)
+		*slashes = '\0';
+	strlcpy(realdst, dst, (size_t)PATH_MAX);
+	if ((slashes = strstr(realdst, "//")) != NULL)
+		*slashes = '\0';
+
 	/* resolve codeset name aliases */
 #ifdef _PATH_ICONV
+	/*
+	 * Note that the below reads from realsrc and realdst while it's
+	 * repopulating (writing to) realsrc and realdst, but it's done so with
+	 * a trip through `buf`.
+	 */
 	snprintf(path, sizeof(path), "%s/%s", _PATH_ICONV, _CITRUS_ICONV_ALIAS);
-	strlcpy(realsrc, _lookup_alias(path, src, buf, (size_t)PATH_MAX,
+	strlcpy(realsrc, _lookup_alias(path, realsrc, buf, (size_t)PATH_MAX,
 	    _LOOKUP_CASE_IGNORE), (size_t)PATH_MAX);
-	strlcpy(realdst, _lookup_alias(path, dst, buf, (size_t)PATH_MAX,
+	strlcpy(realdst, _lookup_alias(path, realdst, buf, (size_t)PATH_MAX,
 	    _LOOKUP_CASE_IGNORE), (size_t)PATH_MAX);
-#else
-	strlcpy(realsrc, src, (size_t)PATH_MAX);
-	strlcpy(realdst, dst, (size_t)PATH_MAX);
 #endif
 
 	/* sanity check */