feat(string): add BSD strlcpy/strlcat at level 2

Exact OpenBSD semantics: strlcpy returns strlen(src) and writes at most
size-1 bytes plus NUL; strlcat returns dlen + strlen(src) with
dlen = min(size, strlen(dst)) and never reads past size bytes in dst.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <[email protected]>
This commit is contained in:
2026-08-31 21:14:52 -04:00
co-authored by Sisyphus
parent d23deaa32a
commit d5e390e992
2 changed files with 107 additions and 0 deletions
+56
View File
@@ -0,0 +1,56 @@
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <string.h>
/*
* Append src to dst, NUL-terminating the result within size bytes.
* Return dlen + strlen(src), where dlen = min(size, strlen(dst)): the length
* the result would have had without truncation. dst is never read past
* size bytes. When size is 0 or dlen == size, nothing is written.
*/
size_t
strlcat(char *dst, const char *src, size_t size)
{
char *d;
const char *s;
size_t n;
size_t dlen;
d = dst;
s = src;
n = size;
/* Find the end of dst, stopping after at most size bytes. */
while (n != 0 && *d != '\0')
{
d++;
n--;
}
dlen = (size_t)(d - dst);
n = size - dlen;
if (n != 0)
{
/* Append as much of src as fits, leaving room for the NUL. */
while (*s != '\0')
{
if (n != 1)
{
*d++ = *s;
n--;
}
s++;
}
*d = '\0';
}
/* Count the unwritten remainder of src. */
while (*s != '\0')
{
s++;
}
return dlen + (size_t)(s - src);
}
+51
View File
@@ -0,0 +1,51 @@
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <string.h>
/*
* Copy src to dst, NUL-terminating the result, truncated to fit size bytes.
* Return strlen(src): the length of the string the call tried to create,
* independent of any truncation. When size is 0, nothing is written.
*/
size_t
strlcpy(char *dst, const char *src, size_t size)
{
const char *orig_src;
size_t nleft;
orig_src = src;
nleft = size;
/* Copy as many bytes as will fit, leaving room for the NUL. */
if (nleft != 0)
{
while (--nleft != 0)
{
*dst = *src;
if (*src == '\0')
{
break;
}
dst++;
src++;
}
}
/* No room for a NUL (or size was 0): NUL-terminate and measure src. */
if (nleft == 0)
{
if (size != 0)
{
*dst = '\0';
}
while (*src != '\0')
{
src++;
}
}
/* src ends at its NUL either way, so this is strlen(original src). */
return (size_t)(src - orig_src);
}