Opened 8 months ago
Closed 8 months ago
#69571 closed enhancement (fixed)
Add stpncpy to legacy support
Reported by: | ryandesign (Ryan Carsten Schmidt) | Owned by: | fhgwright (Fred Wright) |
---|---|---|---|
Priority: | Normal | Milestone: | |
Component: | ports | Version: | |
Keywords: | Cc: | mascguy (Christopher Nielsen) | |
Port: | legacy-support |
Description
Change History (5)
comment:1 Changed 8 months ago by ryandesign (Ryan Carsten Schmidt)
comment:2 Changed 8 months ago by mascguy (Christopher Nielsen)
Given the relatively simple logic involved, I was expecting implementations of stpncpy
to be reasonably similar. But just two variations alone - one originating from gcc
, the other from libc
- tell a different tale:
GCC - via opensource.apple.com/source/gcc/gcc-5465/libiberty/stpncpy.c.auto.html:
char *stpncpy(char *dst, const char *src, size_t len) { size_t n = strlen(src); if (n > len) n = len; return strncpy(dst, src, len) + n; }
LIBC - via opensource.apple.com/source/Libc/Libc-825.26/string/stpncpy.c.auto.html:
char *stpncpy(char * restrict dst, const char * restrict src, size_t maxlen) { const size_t srclen = strnlen(src, maxlen); if (srclen < maxlen) { // The stpncpy() and strncpy() functions copy at most maxlen // characters from src into dst. memcpy(dst, src, srclen); // If src is less than maxlen characters long, the remainder // of dst is filled with '\0' characters. memset(dst+srclen, 0, maxlen-srclen); // The stpcpy() and stpncpy() functions return a pointer to the // terminating '\0' character of dst. return dst+srclen; } else { // The stpncpy() and strncpy() functions copy at most maxlen // characters from src into dst. memcpy(dst, src, maxlen); // If stpncpy() does not terminate dst with a NUL character, it // instead returns a pointer to src[maxlen] (which does not // necessarily refer to a valid memory location.) return dst+maxlen; } }
And a 3rd, from https://lore.kernel.org/dash/6cacf608-326e-211a-7d37-164041710980@knaff.lu/:
char *stpncpy(char *dst, const char *src, int len) { int i,nullSeen=0; char *ret=dst+len; for(i=0; i<len; i++) { if(nullSeen) dst[i] = '\0'; else { dst[i] = src[i]; if(dst[i] == '\0') { nullSeen = 1; ret = dst+i; } } } return ret; }
So we apparently have an embarrassment of riches...
comment:3 Changed 8 months ago by fhgwright (Fred Wright)
I was about to attack this, so you can feel free to assign it to me.
The obvious thing to do is to copy Apple's implementation from the later OS versions where they provide them. It looks like this happened in Libc-825.24
, and never changed since. It's a dumb two-pass implementation (as is the GCC version shown above) that fails to avoid the extra overhead that motivated stpcpy()/stpncpy()
in the first place, but in keeping with the philosophy of never doing anything better than Apple in legacy-support
, it makes sense. Thus, the only real benefit over strcpy()/strncpy()
is in compatibility and convenience.
The larger part of the work is in creating tests, since Apple doesn't have any. One could argue that adding tests for code copied verbatim from Apple shouldn't really be necessary, but in the interests of completeness, it makes sense to add them.
comment:4 Changed 8 months ago by mascguy (Christopher Nielsen)
Cc: | mascguy added; fhgwright removed |
---|---|
Owner: | changed from mascguy to fhgwright |
comment:5 Changed 8 months ago by fhgwright (Fred Wright)
Resolution: | → fixed |
---|---|
Status: | assigned → closed |
dash, for example, currently fails to build on Mac OS X 10.6 and earlier because of the lack of
stpncpy
; see #69572. And this prevents the installation of other ports, like littleutils, that depend on dash.