Hi Bruno,
On 2026-02-25T08:09:46+0100, Bruno Haible wrote:
> Hi Alejandro,
>
> > > Oh wait. Should we have called the new function stpnul() instead of
> > > strnul()?
> > > Because it returns a pointer.
> >
> > ... We have other
> > existing APIs that only have a variant that return an offset pointer,
> > and their name is str*(), strchr(3) being the canonical example.
> > stp*() would only be necessary where there's the two variants with the
> > same name.
>
> OK for keeping strnul then.
>
> Among the str* functions that return a pointer (strchr, strrchr, strdup,
> strpbrk, strstr), there is in particular strpbrk, which can be defined as
>
> char *
> strpbrk (const char *s, const char *char_set)
> {
> size_t n = strcspn (s, char_set);
> return s[n] ? (char *) &s[n] : NULL;
> }
>
> So, as I understand it,
> - stpcspn would be a variant of strpbrk,
> - but stpspn is not such a variant.
Your message prompted me to do some work in the manual pages, to clarify
the incestuous relationship between string APIs. :)
> * If we add only the stpspn function, we'll have tricky-to-remember
> differences between stpspn and strpbrk.
I've added the following text in strcspn(3):
It is equivalent to
(strpbrk(s, reject) ?: strnul(s)) ‐ s
stpspn(3) has no equivalence to anything else, and can only be
implemented with loops and byte operations.
Similarly, strpbrk(3) has no equivalence to anything else, and can only
be implemented with a loop.
> * Whereas if we add both the stpspn and stpcspn functions, we'll have
> two functions stpcspn, strpbrk that are merely variants of each other.
>
> Neither of which is super desirable.
Here's a diff of the most relevant changes. I've documented the
equivalences of functions to others, wherever possible. This should
help clarify the tricky-to-remember differences you mentioned in the
first point.
$ MANWIDTH=64 diffman-git 6c600ed9a9bc HEAD | grep -v ^-
+++ HEAD:man/man3/stpcpy.3
@@ -24,18 +24,10 @@ DESCRIPTION
stpcpy() is similar to strcpy(3), but returns a pointer to
the terminating null byte in dst.
+ It is equivalent to both of the following expressions:
+ memset(mempcpy(dst, src, strlen(src)), '\0', 1);
+ strcpy(dst, src) + strlen(dst)
RETURN VALUE
This function returns a pointer to the terminating null
+++ HEAD:man/man3/stpncpy.3
@@ -36,23 +36,16 @@ DESCRIPTION
ter sequence is truncated. For the difference between the
two functions, see RETURN VALUE.
+ strncpy()
+ It is equivalent to
+ stpncpy(dst, src, dsize), dst
+ stpncpy()
+ It is equivalent to
+ memset(mempcpy(dst, src, strnlen(src, dsize)), '\0',
+ dsize - strnlen(src, dsize))
RETURN VALUE
strncpy()
+++ HEAD:man/man3/strchr.3
@@ -18,10 +18,20 @@ DESCRIPTION
first occurrence of the character c in the string
s.
+ It is equivalent to both of the following expres‐
+ sions:
+
+ memchr(s, c, strlen(s) + 1)
+ strpbrk(s, (char [2]){c, '\0'})
+
strrchr()
The strrchr() function returns a pointer to the
last occurrence of the character c in the string s.
+ It is equivalent to
+
+ memrchr(s, c, strlen(s) + 1)
+
RETURN VALUE
The strchr() and strrchr() functions return a pointer to
the matched character or NULL if the character is not
+++ HEAD:man/man3/strchrnul.3
@@ -17,6 +17,11 @@ DESCRIPTION
c is not found in s, then it returns a pointer to the null
byte at the end of s.
+ It is equivalent to both of the following expressions:
+
+ strchr(s, c) ?: strnul(s)
+ s + strcspn(s, (char [2]){c, '\0'})
+
RETURN VALUE
The strchrnul() function returns a pointer to the matched
character, or a pointer to the null byte at the end of s
@@ -38,6 +43,6 @@ HISTORY
glibc 2.1.1, FreeBSD 10, NetBSD 8.
SEE ALSO
+ string(3), strchr(3), strnul(3), strcspn(3), strspn(3)
Linux man‐pages (unreleased) (date) strchrnul(3)
+++ HEAD:man/man3/strcmp.3
@@ -28,11 +28,19 @@ DESCRIPTION
• a positive value if s1 is greater than s2.
+ It is equivalent to
+
+ memcmp(s1, s2, MIN(strlen(s1),strlen(s2))+1)
+
strncmp()
The strncmp() function is similar, except it com‐
pares only the first (at most) n bytes of s1 and
s2.
+ It is equivalent to
+
+ memcmp(s1, s2, MIN(MIN(strnlen(s1,n),strnlen(s2,n))+1,
n))
+
RETURN VALUE
The strcmp() and strncmp() functions return an integer
less than, equal to, or greater than zero if s1 (or the
+++ HEAD:man/man3/strcpy.3
@@ -19,6 +19,10 @@ DESCRIPTION
programmer is responsible for allocating a destina‐
tion buffer large enough, that is, strlen(src) + 1.
+ It is equivalent to
+
+ stpcpy(dst, src), dst
+
strcat()
This function catenates the string pointed to by
src, after the string pointed to by dst (overwrit‐
@@ -27,23 +31,9 @@ DESCRIPTION
large enough, that is, strlen(dst) + strlen(src) +
1.
+ It is equivalent to
+ stpcpy(strnul(dst), src), dst
RETURN VALUE
These functions return dst.
+++ HEAD:man/man3/strdupa.3
@@ -19,10 +19,18 @@ DESCRIPTION
strdupa() is similar to strdup(3), but uses al‐
loca(3) to allocate the buffer.
+ It is equivalent to
+
+ strcpy(alloca(strlen(s) + 1), s)
+
strndupa()
strndupa() is similar to strndupa(3), but uses al‐
loca(3) to allocate the buffer.
+ It is equivalent to
+
+ strncat(strcpy(alloca(n + 1), ""), s, n)
+
RETURN VALUE
On success, these macros return a pointer to the dupli‐
cated string.
+++ HEAD:man/man3/streq.3
@@ -15,6 +15,10 @@ DESCRIPTION
streq() determines whether the strings s1 and s2 are
equal.
+ It is equivalent to
+
+ strcmp(s1, s2) == 0
+
RETURN VALUE
streq() returns true if and only if the strings s1 and s2
are equal.
+++ HEAD:man/man3/strlen.3
@@ -16,6 +16,10 @@ DESCRIPTION
pointed to by s, excluding the terminating null byte
('\0').
+ It is equivalent to
+
+ strnul(s) ‐ s
+
RETURN VALUE
The strlen() function returns the number of bytes in the
string pointed to by s.
+++ HEAD:man/man3/strncat.3
@@ -22,16 +22,9 @@ DESCRIPTION
enough, that is, the buffer size must be at least
strlen(dst) + strnlen(src, ssize) + 1.
+ It is equivalent to
+ stpcpy(mempcpy(strnul(dst), src, strnlen(src, ssize)), ""),
dst
RETURN VALUE
strncat() returns dst.
+++ HEAD:man/man3/strnlen.3
@@ -27,6 +27,10 @@ DESCRIPTION
looks only at the first maxlen characters in the string
pointed to by s and never beyond s[maxlen-1].
+ It is equivalent to
+
+ (memchr(s, '\0', maxlen) ?: s + maxlen) ‐ s
+
RETURN VALUE
The strnlen() function returns strlen(s), if that is less
than maxlen, or maxlen if there is no null terminating
+++ HEAD:man/man3/strnul.3
@@ -16,6 +16,11 @@ DESCRIPTION
strnul() calculates the position of the terminating null
byte ('\0') in the string pointed to by s.
+ It is equivalent to both of the following expressions:
+
+ s + strlen(s)
+ strchr(s, '\0')
+
RETURN VALUE
strnul() returns a pointer to the terminating null byte in
the string pointed to by s.
+++ HEAD:man/man3/strspn.3
@@ -23,6 +23,10 @@ DESCRIPTION
initial segment of s which consists entirely of
bytes not in reject.
+ It is equivalent to
+
+ (strpbrk(s, reject) ?: strnul(s)) ‐ s
+
RETURN VALUE
The strspn() function returns the number of bytes in the
initial segment of s which consist only of bytes from ac‐
+++ HEAD:man/man3/strstr.3
@@ -21,6 +21,10 @@ DESCRIPTION
substring needle in the string haystack. The terminating
null bytes ('\0') are not compared.
+ It is equivalent to
+
+ memmem(haystack, strlen(haystack), needle, strlen(needle))
+
The strcasestr() function is like strstr(), but ignores
the case of both arguments.
Have a lovely night!
Alex
--
<https://www.alejandro-colomar.es>
signature.asc
Description: PGP signature
