diff --git a/configure.ac b/configure.ac index ecf9fb27..f4c29ca4 100644 --- a/configure.ac +++ b/configure.ac @@ -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. diff --git a/lib/stpecpy.h b/lib/stpecpy.h new file mode 100644 index 00000000..e2c2f479 --- /dev/null +++ b/lib/stpecpy.h @@ -0,0 +1,92 @@ +/* + * SPDX-FileCopyrightText: 2022 - 2023, Alejandro Colomar + * + * SPDX-License-Identifier: BSD-3-Clause + */ + + +#ifndef SHADOW_INCLUDE_LIB_STPECPY_H_ +#define SHADOW_INCLUDE_LIB_STPECPY_H_ + + +#include + +#if !defined(HAVE_STPECPY) + +#include +#include +#include + +#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 diff --git a/libmisc/Makefile.am b/libmisc/Makefile.am index 870da0b8..655fd4bf 100644 --- a/libmisc/Makefile.am +++ b/libmisc/Makefile.am @@ -62,6 +62,7 @@ libmisc_la_SOURCES = \ setugid.c \ setupenv.c \ shell.c \ + stpecpy.c \ stpeprintf.c \ strtoday.c \ sub.c \ diff --git a/libmisc/stpecpy.c b/libmisc/stpecpy.c new file mode 100644 index 00000000..faa02d69 --- /dev/null +++ b/libmisc/stpecpy.c @@ -0,0 +1,20 @@ +/* + * SPDX-FileCopyrightText: 2022 - 2023, Alejandro Colomar + * + * SPDX-License-Identifier: BSD-3-Clause + */ + + +#include + +#if !defined(HAVE_STPECPY) + +#ident "$Id$" + +#include "stpecpy.h" + + +extern inline char *stpecpy(char *dst, char *end, const char *restrict src); + + +#endif // !HAVE_STPECPY