Hi Paul,

On Fri, Sep 19, 2025 at 01:18:57AM -0700, Paul Eggert wrote:
> On 2025-09-18 18:10, Alejandro Colomar wrote:
> > My original proposal was
> > 
> >     strprefix(), stpprefix()
> >     strsuffix(), stpsuffix()
> 
> There is a tension between following the standard naming conventions
> (str[a-z]*, mem[a-z]*) and having readable names. I expect the C committee
> would look with more favor on names that follow existing naming conventions,
> even if they're a bit less readable.
> 
> Gnulib already has names str_startswith and str_endswith for the boolean
> flavors. Perhaps we can add just the pointer flavors, and use
> more-standardish names. strprefix and strsuffix are reasonably easy to read
> and understand; stpprefix and stpsuffix less so. So one possibility is to
> implement strprefix and strsuffix in Gnulib, using a pointer API.

That would be fine.  Actually, stppreffix and suffix was my second
proposal, because the committee wanted to separate the pointer and the
bool variants.  My first proposal was a single set of functions, as I
think the pointer-returning variants are fine to use as booleans too.
After all, I don't expect people to be using these as callbacks anywhere
close to streq.

I think that division was a design-by-committee mistake.  So, I'm fully
in favour of having them as only strprefix() and strsuffix() returning a
pointer, and having no bool variant at all.

> The classic problem with a pointer API, though, is that it's not
> polymorphic. strchr, for example, accepts char const * but returns char *
> and that is a pain.

Since C23, that's not true anymore.  C23 specifies these as
const-generic macros using _Generic().  (The standard calls them
generic functions, but they mean macros.)

<https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3220.pdf#subsection.7.26.5>
<https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3220.pdf#subsubsection.7.26.5.6>

This is the new specification of strrchr(3):

        QChar *strrchr(QChar *s, int c);

For strprefix(), this is how I did it in shadow utils:

        alx@devuan:~/src/shadow/shadow/master$ grepc -h strprefix .
        #define strprefix(s, prefix)                                          \
        ({                                                                    \
                const char  *p_;                                              \
                                                                              \
                p_ = strprefix_(s, prefix);                                   \
                                                                              \
                _Generic(s,                                                   \
                        const char *:                     p_,                 \
                        const void *:                     p_,                 \
                        char *:        const_cast(char *, p_),                \
                        void *:        const_cast(char *, p_)                 \
                );                                                            \
        })
        alx@devuan:~/src/shadow/shadow/master$ grepc -htfd strprefix_ .
        inline const char *
        strprefix_(const char *s, const char *prefix)
        {
                if (strncmp(s, prefix, strlen(prefix)) != 0)
                        return NULL;

                return s + strlen(prefix);
        }
        alx@devuan:~/src/shadow/shadow/master$ grepc -h const_cast .
        #define const_cast(T, p)  _Generic(p, const T:  (T) (p))

(const_cast() is unnecessary; I just wanted to add some safety checks
 in the cast.)

> We could work around this problem by having strprefix
> and strsuffix return a length rather than a pointer. But perhaps I'm
> starting to bikeshed too much here.

I've tried, but it's not possible.  By returning a length, you loose the
ability to return a null pointer if it is not found, which is essential.


Have a lovely day!
Alex

-- 
<https://www.alejandro-colomar.es>
Use port 80 (that is, <...:80/>).

Attachment: signature.asc
Description: PGP signature

Reply via email to