From 680220e772dfa381829983fa73b915416f676894 Mon Sep 17 00:00:00 2001
From: Joshua Watt <JPEWhacker@gmail.com>
Date: Tue, 19 Nov 2019 12:47:30 -0600
Subject: [PATCH] stdlib: Add strlcat

Adds strlcat which can be used to safely concatenate strings

Upstream-Status: Submitted [https://bugzilla.nasm.us/show_bug.cgi?id=3392635]
Signed-off-by: Joshua Watt <JPEWhacker@gmail.com>

---
 Makefile.in        |  2 +-
 configure.ac       |  2 ++
 include/compiler.h |  4 ++++
 stdlib/strlcat.c   | 42 ++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 49 insertions(+), 1 deletion(-)
 create mode 100644 stdlib/strlcat.c

diff --git a/Makefile.in b/Makefile.in
index fcf33ab..d91f7ab 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -174,7 +174,7 @@ LIBOBJ_W = \
 # files to LIBOBJ_W, notably $(OUTPUTOBJ)
 LIBOBJ_NW = \
 	stdlib/snprintf.$(O) stdlib/vsnprintf.$(O) stdlib/strlcpy.$(O) \
-	stdlib/strnlen.$(O) stdlib/strrchrnul.$(O) \
+	stdlib/strnlen.$(O) stdlib/strrchrnul.$(O) stdlib/strlcat.$(O) \
 	\
 	asm/directbl.$(O) \
 	asm/pptok.$(O) \
diff --git a/configure.ac b/configure.ac
index 448eeb2..f79c96c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -229,6 +229,7 @@ PA_FUNC_SNPRINTF
 PA_FUNC_VSNPRINTF
 AC_CHECK_FUNCS([strlcpy])
 AC_CHECK_FUNCS([strrchrnul])
+AC_CHECK_FUNCS([strlcat])
 
 dnl These types are POSIX-specific, and Windows does it differently...
 AC_CHECK_TYPES([struct stat], [AC_CHECK_FUNCS([stat fstat])])
@@ -246,6 +247,7 @@ AC_CHECK_DECLS(strsep)
 AC_CHECK_DECLS(strlcpy)
 AC_CHECK_DECLS(strnlen)
 AC_CHECK_DECLS(strrchrnul)
+AC_CHECK_DECLS(strlcat)
 
 dnl Check for missing types
 AC_TYPE_UINTMAX_T
diff --git a/include/compiler.h b/include/compiler.h
index 0ecd4e8..41c1cbf 100644
--- a/include/compiler.h
+++ b/include/compiler.h
@@ -181,6 +181,10 @@ size_t strlcpy(char *, const char *, size_t);
 char * pure_func strrchrnul(const char *, int);
 #endif
 
+#if !defined(HAVE_STRLCAT) || !HAVE_DECL_STRLCAT
+size_t strlcat(char *, const char *, size_t);
+#endif
+
 #if !defined(__cplusplus) || (__STDC_VERSION >= 202311L)
 /* C++ and C23 have bool, false, and true as proper keywords */
 # ifdef HAVE_STDBOOL_H
diff --git a/stdlib/strlcat.c b/stdlib/strlcat.c
new file mode 100644
index 0000000..c7cbd59
--- /dev/null
+++ b/stdlib/strlcat.c
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2019 Garmin Ltd. or its subsidiaries
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "compiler.h"
+
+/*
+ * Concatenate src string to dest of size size. The destination buffer will
+ * have no more than size-1 character when the operation finishes. Always NUL
+ * terminates, unless size == 0 or dest has no NUL terminator. Returns
+ * strlen(initial dest) + strlen(src); if retval >= size, truncation occurred.
+ */
+#ifndef HAVE_STRLCAT
+
+size_t strlcat(char *dest, const char *src, size_t size)
+{
+    size_t n;
+
+    /* find the NULL terminator in dest */
+    for (n = 0; i < size && dest[n] != '\0'; n++)
+        ;
+
+    /* destination was not NULL terminated. Return the initial size */
+    if (n == size)
+        return size;
+
+    return strlcpy(&dest[n], src, size - n) + n;
+}
+
+#endif
