Libc Bringup: String Functions

Continuing with our libc bringup, it's time to tackle some of the string functions:

I also want to support the FreeBSD functions below:

These functions have been used on many systems I've worked on, and they provide a valuable basis to start from when working on libcpp.

Files Directly Imported From Apple Open Source

Finding quality string function implementations is pretty easy: people love optimizing them. Most of the string-related functions are well-implemented and directly usable.

I prefer using the Apple Open Source version of these functions:

You'll find that I have directly imported these functions into embedded-resources.

My Own Implementations

I don't like to reinvent the wheel - I've brought up too many systems at this point, and I'm annoyed by reimplementing the same funtions for the Nth time.

That being said, sometimes I'm not happy with the implementations that are available on the web. strcmp and strncmp are two such functions. I don't like the musl implementation and the Apple Open Source versions are in assembly. Right now, I just want generic C versions of the functions. Let's take a look at what I put together.

strcmp

I like when my strcmp-like functions short-circuit: it's a common optimization to have const strings combined together by the compiler for more efficient storage. Otherwise this strcmp compares strings as expected, and bails out when string 1 ends (via NULL termination)

int strcmp(const char *s1, const char *s2)
{
    int r = -1;

    if (s1 == s2)
    {
        //short circuit - same string
        return 0;
    }

    //I don't want to panic with a NULL ptr - we'll fall through and fail w/ -1
    if (s1 != NULL && s2 != NULL)
    {
        //iterate through strings until they don't match or s1 ends (null-term)
        for (; *s1 == *s2; ++s1, ++s2)
        {
            if (*s1 == 0)
            {
                r = 0;
                break;
            }
        }

        // handle case where we didn't break early - set return code.
        if(r != 0)
        {
            r = *(char *)s1 - *(char *)s2;
        }
    }

    return r;
}

strncmp

The strncmp implementation below is similar to my strcmp implemntation, but now we also the check size of the string.

The only change is in the for loop, as we need to handle our input size n:

for (; n && *s1 == *s2; ++s1, ++s2, n--)

It's as simple as that!

Source Code

You can find the string functions in the libc folder in the embedded-resources project.

Please feel free to use or amend these as you please!

string.h

Reviewing our string.h file, we now have support for the following functions. We're making some progress!

#pragma mark - memory -

int memcmp(const void * s1, const void * s2, size_t n);
void *memset(void * dest, int c, size_t n);
void *memcpy(void * __restrict dest, const void * __restrict src, size_t n);
void *memmove(void * dest, const void * src, size_t n);
void *memchr(const void *s, int c, size_t n);

#pragma mark - string -

size_t strlen(const char *str);
size_t strnlen(const char *str, size_t maxlen);
char *strcpy(char * restrict dst, const char * restrict src);
char *strncpy(char * restrict dst, const char * restrict src, size_t maxlen);
char *strnstr(const char *s, const char *find, size_t slen);
int strcmp(const char *s1, const char *s2);
int strncmp(const char *s1, const char *s2, size_t n);
char *strdup(const char *str);
char *strndup(const char *str, size_t n);

Further Reading