Your proposal isn't an improvement over the current situation with strl* functions, and I don't think this is helpful.
Alejandro Colomar (man-pages) <[email protected]> wrote: > Hi, Todd and Theo! > > I wrote this function this week, based on strlcpy(3) and strecopy()[1], > which are the best string copy functions I've seen so far. But I came > to improvements that bring one function that I think is better than both > of those. > > I posted the function for review on codidact.com[2]. > I also discussed it a bit on the groff@ mailing list[3]. > > See this manual page I wrote for it. Since you designed strlcpy(3BSD) > and strlcat(3BSD), I'm interested in knowing your opinion on it. If you > like it, feel free to add it to OpenBSD. ;-) > > Cheers, > > Alex > > > [1]: <https://www.symas.com/post/the-sad-state-of-c-strings> > [2]: <https://software.codidact.com/posts/285946/285952#answer-285952> > [3]: <https://lists.gnu.org/archive/html/groff/2022-02/msg00050.html> > > > --- > stpecpy(3) Linux Programmer’s Manual stpecpy(3) > > NAME > stpecpy - bounded string copy and concatenation > > SYNOPSIS > #include <string.h> > > char *_Nonnull stpecpy(char *_Nonnull dest, > const char *_Nonnull restrict src, > char *_Nonnull end); > > DESCRIPTION > stpecpy() copies the string pointed to by src (including > the terminating null byte ('\0')) to the array pointed to > by dest. The strings may not overlap. This function > doesn’t overflow the destination buffer, and requires a > pointer to the end of it for that purpose. > > end is a pointer to the last element in the dest buffer. > It should be calculated in the following way: > > char dest[SIZE]; > char *end; > > end = &dest[SIZE - 1]; > stpecpy(dest, "Hello world", end); > > This function only operates on true "C" strings, which > means that src must be terminated by a null byte, and > dest is guaranteed to be terminated with a null byte af‐ > ter the call (as long as the buffer has a size larger > than 0). > > This function is designed to be a safer, more consistent, > less error prone, and simpler replacement for other > string copy and concatenation functions. > > Compared to other string copy and concatenation functions > strlcat(3BSD) > *cat() functions have an inherent performance > problem: each *cat() call has to find again the > teminating null byte in the dest string. Read > about Shlemiel the painter’s algorithm > ⟨https://www.joelonsoftware.com/2001/12/11/back- > to-basics/⟩. > > strlcpy(3BSD) > strscpy(9) > memccpy(3) > One can use strlcpy(3BSD), strscpy(9), or > memccpy(3) to concatenate, without strlcat(3BSD), > but it’s error prone. They require the user to > recalculate the remaining buffer size for every > call. > > stpcpy(3) > It can’t detect overflow. However, in case the > programmer knows overflow can’t occur, then it’s > simpler to use it. > > stpncpy(3) > strncpy(3) > strncat(3) > They don’t work with "C" strings. The resulting > string is not guaranteed to be terminated with a > null byte. They also write unnecessary zeros af‐ > ter the terminating byte. > > strcpy(3) > It doesn’t detect overflow, as stpcpy(3), plus it > can’t be chained; requires strcat(3). > > strcat(3) > It can’t detect overflow, as strcpy(3), plus it > has performance problems, as strlcat(3BSD). > > snprintf(3) > It has considerable overhead, which can be orders > of magnitude slower. > > RETURN VALUE > stpecpy() returns a pointer to the terminating null byte > in dest, except if the string has been truncated, in > which case it returns end + 1. > > EXAMPLES > Trivial (not optimized) implementation: > char *_Nonnull > stpecpy(char *_Nonnull dst, char *_Nonnull restrict src, > char *_Nonnull end) > { > for (/* void */; dst <= end; dst++, src++) { > *dst = *src; > if (*dst == '\0') > return dst; > } > /* truncation detected */ > *end = '\0'; > return dst; > } > > Example of usage > The following program produces this output: > > $ ./a.out > Trunc: 9: Hello wor > 9: Hello foo > Trunc: 9: Hello baa > 2: HW > > Source code: > > int > main(void) > { > ptrdiff_t size = 10; > char buf[size]; > char *end; > ptrdiff_t len; > > end = &buf[size - 1]; > > len = stpecpy(stpecpy(buf, "Hello", end), " world", end) > - buf; > if (len == size) { > len--; > printf("Trunc: "); > } > printf("%ti: %s\n", len, buf); > > len = stpecpy(stpecpy(stpecpy(buf, "Hello", end), " foo", > end), > "", end) - buf; > if (len == size) { > len--; > printf("Trunc: "); > } > printf("%ti: %s\n", len, buf); > > len = stpecpy(stpecpy(stpecpy(buf, "Hello", end), " > baar", end), > "", end) - buf; > if (len == size) { > len--; > printf("Trunc: "); > } > printf("%ti: %s\n", len, buf); > > len = stpecpy(stpecpy(buf, "H", end), "W", end) - buf; > if (len == size) { > len--; > printf("Trunc: "); > } > printf("%ti: %s\n", len, buf); > } > > SEE ALSO > snprintf(3), strncat(3), strncpy(3), stpsecpy(3) > > alx 2022-02-13 stpecpy(3) > > > -- > Alejandro Colomar > Linux man-pages comaintainer; https://www.kernel.org/doc/man-pages/ > http://www.alejandro-colomar.es/
