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)

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.

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 the first three variations I reviewed, are quite different indeed.

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...

Last edited 8 months ago by mascguy (Christopher Nielsen) (previous) (diff)

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.

Last edited 8 months ago by fhgwright (Fred Wright) (previous) (diff)

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: assignedclosed

In 12a4dca86937f7d072f8ed64fd7df91b60619a41/macports-legacy-support (master):

Add stpncpy() support

Imports Apple's stpncpy.c verbatim from Libc-825.24.

Removes 'restrict' qualifiers for pre-C99 compatibility.

Fixes whitespace; adds modification notice and proper build
conditional.

Updates the legacy-support headers.

Updates the README.

Closes: #69571

TESTED:
Tested on 10.4-10.5 ppc, 10.4-10.6 i386, 10.5-10.6 ppc (i386 Rosetta),
10.5-12.x x86_64, 11.x-14.x arm64.
Passes all tests, including newly added stpncpy() tests.

Note: See TracTickets for help on using tickets.