Non-Standard Function: strcasecmp()

As part of my research, I run my C code on different platforms using different compilers. Occasionally I’m crushed to discover that my code won’t compile because my development computer uses a customized version of the C library, one that features a non-standard function, such as strcasecmp().

The C17/C18 library standard defines the strcmp() function and its siblings, which compare two strings. It does not define the strcasecmp() function, which works the same as strcmp(), but ignores the difference between uppercase and lowercase letters.

Surprising, many libraries are littered with non-standard C functions. They’re documented, but the man page doesn’t proclaim that the functions are non-standard:

The strcasecmp() and strncasecmp() functions first appeared in 4.4BSD. Their prototypes existed previously in before they were moved to <strings.h> for IEEE Std 1003.1-2001 (“POSIX.1”) compliance.

A quick look in the string.h header file on my system confirms that it also includes the (non-standard) strings.h header file, in which the strcasecmp() function is defined. Sneaky.

Without knowing otherwise, I’ve used strcasecmp() in several programs. Only when I attempted to build the code on another system do I discover that the function isn’t defined. Yeah, that ticks me off a tad.

Digging into the topic of non-standard functions further, I discovered two more: strlcpy() and strlcat(). I’m certain other non-standard functions exist as well, available in one C library but not another. Yet, these functions serve valid purposes.

Like strcpy() and strcat() functions, strlcpy() and strlcat() copy and concatenate strings, respectively. The difference is in a new, third argument, which sets a size limit for the destination string. This addition makes the functions safer than their standard C library counterparts — an excellent improvement.

The good news is that if your compiler’s C library fails to implement these functions, you can code them yourself. Below you see my attempt at replicating the strcasecmp() function. It performs similar to strcasecmp() as documented, returning a value of zero when the strings match (regardless of case) and values less than or greater than zero depending on how the strings compare.

#include <stdio.h>
#include <ctype.h>

int strcasecmp(const char *s1, const char *s2)
{
    int offset,ch;
    unsigned char a,b;

    offset = 0;
    ch = 0;
    while( *(s1+offset) != '\0' )
    {
        /* check for end of s2 */
        if( *(s2+offset)=='\0')
            return( *(s1+offset) );

        a = (unsigned)*(s1+offset);
        b = (unsigned)*(s2+offset);
        ch = toupper(a) - toupper(b);
        if( ch<0 || ch>0 )
            return(ch);
        offset++;
    }

    return(ch);
}

void test(const char *s1, const char *s2)
{
    printf("%s v. %s = ",s1,s2);
    if( strcasecmp(s1,s2)==0 )
        puts("match");
    else
        puts("no match");
}

int main()
{
    char string1[] = "I drink coffee";
    char string2[] = "I DRINK COFFEE";
    char string3[] = "I drink tea";

    test(string1,string1);
    test(string1,string2);
    test(string1,string3);

    return(0);
}

The main() function defines three test strings, which are run through the test() function for comparison and output. The test() function uses my version of the strcasecmp() function to compare the strings, then outputs match or nomatch depending on the results.

The strcasecmp() function (which doesn’t generate a compiler warning in this code because I didn’t include the string.h or strings.h header) uses a while loop to compare both strings, s1 and s2. Both strings are compared letter-by-letter, thanks to the offset variable, at Line 19. At Line 20, if variable ch isn’t equal to zero, its value is returned, otherwise, the while loop continues:

ch = toupper(a) - toupper(b);
if( ch<0 || ch>0 )
    return(ch);

Lines 14 and 15 perform a vital end-of-string test for s2, just in case it’s shorter than s1. If so, the current character in s1 is returned:

if( *(s2+offset)=='\0')
    return( *(s1+offset) );

Here’s sample output:

I drink coffee v. I drink coffee = match
I drink coffee v. I DRINK COFFEE = match
I drink coffee v. I drink tea = no match

For next week’s Lesson I cover a substitute function for strlcpy(). A later Lesson covers strlcat().

3 thoughts on “Non-Standard Function: strcasecmp()

  1. It’s been pointed out that the statement:

    if( ch<0 || ch>0 )

    Can also be written as:

    if( ch!=0 )

    My guess is that the comparison is probably a leftover from an early version of the code, something I combined and didn’t recognize how it can be simplified.

  2. strcmp() and strcasecmp() return the difference between the encoded values of the first pair of characters which are different. Is there any use for this?

  3. I’m unsure how it could be used or would be useful. It might just be a handy return value, especially given that it’s unsigned which means you can’t even determine where the mismatched character is relative to its code value.

Leave a Reply