From cd5f1bd277c1beb7e5fdfa7f3b4db0caf26f6c51 Mon Sep 17 00:00:00 2001 From: Nicklas Larsson Date: Fri, 13 Sep 2024 14:00:45 +0200 Subject: [PATCH] lib/gis: Add portable G_strlcat function (#4304) Add wrapper function for strlcat(), using system function if available, otherwise uses implementation by Todd C. Miller originated from https://github.com/openbsd/src/blob/e291b8af02e5c2b53d7ddb1f0c9c0fd608b97d45/lib/libc/string/strlcat.c. G_strlcat() is a safer alternative to strcat(). --- configure | 17 +++++++- configure.ac | 3 ++ include/grass/config.h.in | 9 +++-- include/grass/defs/gis.h | 3 ++ lib/gis/strlcat.c | 84 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 112 insertions(+), 4 deletions(-) create mode 100644 lib/gis/strlcat.c diff --git a/configure b/configure index 7d8b9b1e5e7..bc60ae7c41c 100755 --- a/configure +++ b/configure @@ -765,8 +765,9 @@ SOCKLIB ICONVLIB DLLIB MATHLIB -HAVE_ASPRINTF HAVE_STRLCPY +HAVE_STRLCAT +HAVE_ASPRINTF DBMIEXTRALIB USE_X11 XTLIB @@ -8312,6 +8313,19 @@ then : fi + + +ac_fn_c_check_func "$LINENO" "strlcat" "ac_cv_func_strlcat" +if test "x$ac_cv_func_strlcat" = xyes +then : + printf "%s\n" "#define HAVE_STRLCAT 1" >>confdefs.h + +fi + + + +# Test if strlcpy exists +# This is a function part of *BSD libc (optionally available on Linux via libbsd) ac_fn_c_check_func "$LINENO" "strlcpy" "ac_cv_func_strlcpy" if test "x$ac_cv_func_strlcpy" = xyes then : @@ -8320,6 +8334,7 @@ then : fi + # Test if mathlib needs -lm flag or is included with libc ac_fn_c_check_func "$LINENO" "atan" "ac_cv_func_atan" if test "x$ac_cv_func_atan" = xyes diff --git a/configure.ac b/configure.ac index 8ef6e1b9f7c..b38a2a5936c 100644 --- a/configure.ac +++ b/configure.ac @@ -595,6 +595,9 @@ AC_SUBST(DBMIEXTRALIB) AC_CHECK_FUNCS(asprintf) AC_SUBST(HAVE_ASPRINTF) +AC_CHECK_FUNCS(strlcat) +AC_SUBST(HAVE_STRLCAT) + # Test if strlcpy exists # This is a function part of *BSD libc (optionally available on Linux via libbsd) AC_CHECK_FUNCS(strlcpy) diff --git a/include/grass/config.h.in b/include/grass/config.h.in index f070b4ccc0d..95dc2bc034b 100644 --- a/include/grass/config.h.in +++ b/include/grass/config.h.in @@ -14,9 +14,6 @@ /* Define to 1 if you have the `asprintf' function. */ #undef HAVE_ASPRINTF -/* Define to 1 if you have the `strlcpy' function. */ -#undef HAVE_STRLCPY - /* Define to 1 if you have the header file. */ #undef HAVE_BZLIB_H @@ -239,6 +236,12 @@ /* Define to 1 if you have the header file. */ #undef HAVE_STRING_H +/* Define to 1 if you have the `strlcat' function. */ +#undef HAVE_STRLCAT + +/* Define to 1 if you have the `strlcpy' function. */ +#undef HAVE_STRLCPY + /* Define to 1 if you have the header file. */ #undef HAVE_SVM_H diff --git a/include/grass/defs/gis.h b/include/grass/defs/gis.h index 4125a3aeed3..dc5ad2499f0 100644 --- a/include/grass/defs/gis.h +++ b/include/grass/defs/gis.h @@ -152,6 +152,9 @@ int G_vfaprintf(FILE *, const char *, va_list); int G_vsaprintf(char *, const char *, va_list); int G_vsnaprintf(char *, size_t, const char *, va_list); +/* strlcat.c */ +size_t G_strlcat(char *, const char *, size_t); + /* strlcpy.c */ size_t G_strlcpy(char *, const char *, size_t); diff --git a/lib/gis/strlcat.c b/lib/gis/strlcat.c new file mode 100644 index 00000000000..ed6c3887e72 --- /dev/null +++ b/lib/gis/strlcat.c @@ -0,0 +1,84 @@ +/*! + * \file lib/gis/strlcat.c + * + * \brief GIS Library - GRASS implementation of strlcat(). + * + * If available, G_strlcat() calls system strlcat(), otherwise it uses + * implementation by Todd C. Miller of OpenBSD. + * + * Addition to GRASS GIS by Nicklas Larsson, 2024 + * + * Original OpenBSD implementation notes: + * + * Copyright (c) 1998, 2015 Todd C. Miller + * + * 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 +#include + +/** + * \brief Size-bounded string concatenation + * + * Appends string src to the end of dst. It will append at most + * dstsize - strlen(dst) - 1 characters. It will then NUL-terminate, unless + * dstsize is 0 or the original dst string was longer than dstsize (in practice + * this should not happen as it means that either dstsize is incorrect or that + * dst is not a proper string). + * + * If the src and dst strings overlap, the behavior is undefined. + * This function is a safer alternative to strncat. + * + * \param[out] dst Pointer to the destination buffer. Must be a NUL-terminated + * C string. + * \param[in] src Pointer to the source string, which will be appended. Must + * be a NUL-terminated C string. + * \param[in] dsize The size of the destination buffer. + * + * \return The total length of the string src, which was attempted to be + * created (the initial length of dst plus the length of src, not + * including the terminating NUL character). If the return value + * is >= dsize, truncation occurred. + */ + +size_t G_strlcat(char *restrict dst, const char *restrict src, size_t dsize) +{ +#ifdef HAVE_STRLCAT + return strlcat(dst, src, dsize); +#else + const char *odst = dst; + const char *osrc = src; + size_t n = dsize; + size_t dlen; + + /* Find the end of dst and adjust bytes left but don't go past end. */ + while (n-- != 0 && *dst != '\0') + dst++; + dlen = dst - odst; + n = dsize - dlen; + + if (n-- == 0) + return (dlen + strlen(src)); + while (*src != '\0') { + if (n != 0) { + *dst++ = *src; + n--; + } + src++; + } + *dst = '\0'; + + return (dlen + (src - osrc)); /* count does not include NUL */ +#endif +}