Name n3613, alx-0020r3 - add strsfx(), stpsfx(), wcssfx(), wcpsfx() Principles - Codify existing practice to address evident deficiencies. - Enable secure programming Category Standardize common APIs Author Alejandro Colomar Cc: Yair Lenga Cc: Joseph Myers Cc: Patrizia Kaye Cc: Christopher Bazley History r0 (2025-06-10): - Initial draft. r1 (2025-06-10; n3596): - tfix. - Rename to strsfx(). r2 (2025-06-12): - tfix - Add bool-returning variants, and adjust names. - Update introductions to search functions. r3 (2025-06-26; n3613): - wfix Rationale Many projects come up with a wrapper stpsfx() to perform a rather common operation: check if a string ends in a suffix, and optionally get a pointer to it (often to remove it, by writing a '\0'). By developing such a wrapper in shadow utils, and replacing code that used manual byte operations(3) to use the wrapper, I've found and fixed several bugs. This API, like stppfx(), needs to return a pointer instead of a bool. This is because a common use case of this API is to remove the suffix. Still, this pointer is boolean-like, in the sense that stpsfx() returns non-null if the suffix is found, and a null pointer if it is not found, so the usual case of just searching for a suffix can be programmed exacly as if this API returned a bool. A bool-returning variant is still useful as a callback compatible with streq(). Prior art Many projects define this API, either as a macro or as a function. I've developed it in shadow-utils as a const-generic macro. Here's an example implementation: #define stpsfx(s, suffix) \ ({ \ const char *s_; \ \ s_ = stpsfx_(s, suffix); \ \ _Generic(s, \ const char *: s_, \ const void *: s_, \ char *: const_cast(char *, s_),\ void *: const_cast(char *, s_) \ ); \ }) const char * stpsfx_(const char *s, const char *suffix) { ptrdiff_t off; off = strlen(s) - strlen(suffix); if (off < 0) return NULL; if (!streq(s + off, suffix)) return NULL; return s + off; } #define const_cast(T, p) _Generic(p, const T: (T) (p)) bool strsfx(const char *s, const char *suffix) { return stpsfx(s, suffix); } Proposed wording Based on N3550. 7.28.5.1 String handling :: Search functions :: Introduction @@ p1 The stateless search functions in this subclause -(memchr, strchr, strpbrk, strrchr, strstr) +(memchr, strchr, strpbrk, strrchr, strstr, stpsfx) are generic functions. ... 7.28.5 String handling :: Search functions ## New sections after 7.28.5.8 ("The strstr function"): +7.28.5.8+1 The stpsfx generic function + +Synopsis +1 #include + QChar *stpsfx(QChar *s, const char *suffix); + +Description +2 The stpsfx generic function + determines whether the string pointed to by s + ends with the sequence of characters + in the string pointed to by suffix. + +Returns +3 The stpsfx generic function returns + s + strlen(s) - strlen(suffix) + if the string ends with the given suffix, + or a null pointer otherwise. + +7.28.5.8+2 The strsfx function + +Synopsis +1 #include + bool strsfx(const char *s, const char *suffix); + +Description +2 The strsfx function + is similar to stpsfx, + but returns a boolean value. + +Returns +3 The strsfx function returns + true + if and only if the string ends with the given suffix. 7.33.4.6 Wide string search functions ## New sections after 7.33.4.6.7 ("The wcsstr function"): +7.33.4.6.7+1 The wcpsfx generic function + +Synopsis +1 #include + QWchar_t *wcpsfx(QWchar_t *s, const wchar_t *suffix); + +Description +2 The wcpsfx generic function + is equivalent to + stpsfx, + except that it handles wide strings. + +7.33.4.6.7+2 The wcssfx function + +Synopsis +1 #include + bool wcssfx(const wchar_t *s, const wchar_t *suffix); + +Description +2 The wcssfx function + is equivalent to + strsfx, + except that it handles wide strings.