Add stpecpy()

strncat(3), strlcpy(3), and many other functions are often misused for
catenating strings, when they should never be used for that.  strlcat(3)
is good.  However, there's no equivalent to strlcat(3) similar to
snprintf(3).  Let's add stpecpy(), which is similar to strlcat(3), but
it is also the only function compatible with stpeprintf(), which makes
it more useful than strlcat(3).

Signed-off-by: Alejandro Colomar <alx@kernel.org>
This commit is contained in:
Alejandro Colomar 2023-02-10 22:34:37 +01:00 committed by Iker Pedrosa
parent e0e9e57a72
commit 709e6b4497
4 changed files with 114 additions and 1 deletions

View File

@ -50,7 +50,7 @@ AC_CHECK_FUNCS(arc4random_buf futimes \
initgroups lckpwdf lutimes mempcpy \
setgroups updwtmp updwtmpx innetgr \
getspnam_r \
memset_explicit explicit_bzero stpeprintf)
memset_explicit explicit_bzero stpecpy stpeprintf)
AC_SYS_LARGEFILE
dnl Checks for typedefs, structures, and compiler characteristics.

92
lib/stpecpy.h Normal file
View File

@ -0,0 +1,92 @@
/*
* SPDX-FileCopyrightText: 2022 - 2023, Alejandro Colomar <alx@kernel.org>
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef SHADOW_INCLUDE_LIB_STPECPY_H_
#define SHADOW_INCLUDE_LIB_STPECPY_H_
#include <config.h>
#if !defined(HAVE_STPECPY)
#include <stdbool.h>
#include <stddef.h>
#include <string.h>
#include "defines.h"
inline char *stpecpy(char *dst, char *end, const char *restrict src);
/*
* SYNOPSIS
* char *_Nullable stpecpy(char *_Nullable dst, char end[0],
* const char *restrict src);
*
* ARGUMENTS
* dst Destination buffer where to copy a string.
*
* end Pointer to one after the last element of the buffer
* pointed to by `dst`. Usually, it should be calculated
* as `dst + NITEMS(dst)`.
*
* src Source string to be copied into dst.
*
* DESCRIPTION
* This function copies the string pointed to by src, into a string
* at the buffer pointed to by dst. If the destination buffer,
* limited by a pointer to its end --one after its last element--,
* isn't large enough to hold the copy, the resulting string is
* truncated.
*
* This function can be chained with calls to [v]stpeprintf().
*
* RETURN VALUE
* dst + strlen(dst)
* On success, this function returns a pointer to the
* terminating NUL byte.
*
* end
* If this call truncated the resulting string.
* If `dst == end` (a previous chained call to these
* functions truncated).
* NULL
* If `dst == NULL` (a previous chained call to
* [v]stpeprintf() failed).
*
* ERRORS
* This function doesn't set errno.
*/
inline char *
stpecpy(char *dst, char *end, const char *restrict src)
{
bool trunc;
char *p;
size_t dsize, dlen, slen;
if (dst == end)
return end;
if (dst == NULL)
return NULL;
dsize = end - dst;
slen = strnlen(src, dsize);
trunc = (slen == dsize);
dlen = slen - trunc;
p = mempcpy(dst, src, dlen);
*p = '\0';
return p + trunc;
}
#endif // !HAVE_STPECPY
#endif // include guard

View File

@ -62,6 +62,7 @@ libmisc_la_SOURCES = \
setugid.c \
setupenv.c \
shell.c \
stpecpy.c \
stpeprintf.c \
strtoday.c \
sub.c \

20
libmisc/stpecpy.c Normal file
View File

@ -0,0 +1,20 @@
/*
* SPDX-FileCopyrightText: 2022 - 2023, Alejandro Colomar <alx@kernel.org>
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <config.h>
#if !defined(HAVE_STPECPY)
#ident "$Id$"
#include "stpecpy.h"
extern inline char *stpecpy(char *dst, char *end, const char *restrict src);
#endif // !HAVE_STPECPY