{"id":3863,"date":"2019-11-30T00:01:22","date_gmt":"2019-11-30T08:01:22","guid":{"rendered":"https:\/\/c-for-dummies.com\/blog\/?p=3863"},"modified":"2019-12-21T08:47:18","modified_gmt":"2019-12-21T16:47:18","slug":"non-standard-function-strcasecmp","status":"publish","type":"post","link":"https:\/\/c-for-dummies.com\/blog\/?p=3863","title":{"rendered":"Non-Standard Function: <em>strcasecmp()<\/em>"},"content":{"rendered":"<p>As part of my research, I run my C code on different platforms using different compilers. Occasionally I&#8217;m crushed to discover that my code won&#8217;t compile because my development computer uses a customized version of the C library, one that features a non-standard function, such as <em>strcasecmp()<\/em>.<br \/>\n<!--more--><br \/>\nThe C17\/C18 library standard defines the <em>strcmp()<\/em> function and its siblings, which compare two strings. It does not define the <em>strcasecmp()<\/em> function, which works the same as <em>strcmp()<\/em>, but ignores the difference between uppercase and lowercase letters.<\/p>\n<p>Surprising, many libraries are littered with non-standard C functions. They&#8217;re documented, but the <em>man<\/em> page doesn&#8217;t proclaim that the functions are non-standard:<\/p>\n<blockquote><p>The <em>strcasecmp()<\/em> and <em>strncasecmp()<\/em> functions first appeared in 4.4BSD. Their prototypes existed previously in <code><string.h><\/code> before they were moved to <code>&lt;strings.h&gt;<\/code> for IEEE Std 1003.1-2001 (&#8220;POSIX.1&#8221;) compliance.<\/p><\/blockquote>\n<p>A quick look in the <code>string.h<\/code> header file on my system confirms that it also includes the (non-standard) <code>strings.h<\/code> header file, in which the <em>strcasecmp()<\/em> function is defined. Sneaky.<\/p>\n<p>Without knowing otherwise, I&#8217;ve used <em>strcasecmp()<\/em> in several programs. Only when I attempted to build the code on another system do I discover that the function isn&#8217;t defined. Yeah, that ticks me off a tad.<\/p>\n<p>Digging into the topic of non-standard functions further, I discovered two more: <em>strlcpy()<\/em> and s<em>trlcat()<\/em>. I&#8217;m certain other non-standard functions exist as well, available in one C library but not another. Yet, these functions serve valid purposes.<\/p>\n<p>Like <em>strcpy()<\/em> and <em>strcat()<\/em> functions, <em>strlcpy()<\/em> and <em>strlcat()<\/em> 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 &mdash; an excellent improvement.<\/p>\n<p>The good news is that if your compiler&#8217;s C library fails to implement these functions, you can code them yourself. Below you see my attempt at replicating the <em>strcasecmp()<\/em> function. It performs similar to <em>strcasecmp()<\/em> 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.<\/p>\n<pre class=\"screen\">\r\n#include &lt;stdio.h&gt;\r\n#include &lt;ctype.h&gt;\r\n\r\nint strcasecmp(const char *s1, const char *s2)\r\n{\r\n    int offset,ch;\r\n    unsigned char a,b;\r\n\r\n    offset = 0;\r\n    ch = 0;\r\n    while( *(s1+offset) != '\\0' )\r\n    {\r\n        <span class=\"comments\">\/* check for end of s2 *\/<\/span>\r\n        if( *(s2+offset)=='\\0')\r\n            return( *(s1+offset) );\r\n\r\n        a = (unsigned)*(s1+offset);\r\n        b = (unsigned)*(s2+offset);\r\n        ch = toupper(a) - toupper(b);\r\n        if( ch&lt;0 || ch&gt;0 )\r\n            return(ch);\r\n        offset++;\r\n    }\r\n\r\n    return(ch);\r\n}\r\n\r\nvoid test(const char *s1, const char *s2)\r\n{\r\n    printf(\"%s v. %s = \",s1,s2);\r\n    if( strcasecmp(s1,s2)==0 )\r\n        puts(\"match\");\r\n    else\r\n        puts(\"no match\");\r\n}\r\n\r\nint main()\r\n{\r\n    char string1[] = \"I drink coffee\";\r\n    char string2[] = \"I DRINK COFFEE\";\r\n    char string3[] = \"I drink tea\";\r\n\r\n    test(string1,string1);\r\n    test(string1,string2);\r\n    test(string1,string3);\r\n\r\n    return(0);\r\n}<\/pre>\n<p>The <em>main()<\/em> function defines three test strings, which are run through the <em>test()<\/em> function for comparison and output. The <em>test()<\/em> function uses my version of the <em>strcasecmp()<\/em> function to compare the strings, then outputs <code>match<\/code> or <code>nomatch<\/code> depending on the results.<\/p>\n<p>The <em>strcasecmp()<\/em> function (which doesn&#8217;t generate a compiler warning in this code because I didn&#8217;t include the <code>string.h<\/code> or <code>strings.h<\/code> header) uses a <em>while<\/em> loop to compare both strings, <code>s1<\/code> and <code>s2<\/code>. Both strings are compared letter-by-letter, thanks to the <code>offset<\/code> variable, at Line 19. At Line 20, if variable <code>ch<\/code> isn&#8217;t equal to zero, its value is returned, otherwise, the <em>while<\/em> loop continues:<\/p>\n<p><code>ch = toupper(a) - toupper(b);<br \/>\nif( ch<0 || ch>0 )<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;return(ch);<\/code><\/p>\n<p>Lines 14 and 15 perform a vital end-of-string test for <code>s2<\/code>, just in case it&#8217;s shorter than <code>s1<\/code>. If so, the current character in <code>s1<\/code> is returned:<\/p>\n<p><code>if( *(s2+offset)=='\\0')<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;return( *(s1+offset) );<\/code><\/p>\n<p>Here&#8217;s sample output:<\/p>\n<p><code>I drink coffee v. I drink coffee = match<br \/>\nI drink coffee v. I DRINK COFFEE = match<br \/>\nI drink coffee v. I drink tea = no match<\/code><\/p>\n<p>For <a href=\"https:\/\/c-for-dummies.com\/blog\/?p=3873\">next week&#8217;s Lesson<\/a> I cover a substitute function for <em>strlcpy()<\/em>. <a href=\"https:\/\/c-for-dummies.com\/blog\/?p=3896\">A later Lesson<\/a> covers <em>strlcat()<\/em>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In the first of a short series, non-standard C library functions are discussed and substitutes presented. This week, the <em>strcasecmp<\/em> function is covered, which compares strings regardless of case. <a href=\"https:\/\/c-for-dummies.com\/blog\/?p=3863\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2],"tags":[],"class_list":["post-3863","post","type-post","status-publish","format-standard","hentry","category-main"],"_links":{"self":[{"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/3863","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=3863"}],"version-history":[{"count":8,"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/3863\/revisions"}],"predecessor-version":[{"id":3913,"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/3863\/revisions\/3913"}],"wp:attachment":[{"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=3863"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=3863"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=3863"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}