memmem() Function for a C Program

Last week, I needed a function for a C program that would search a string not null terminated for a string not null terminated. Hence, I could not use strstr() function because it requires the strings to be null terminated. So, I checked my trusty C Runtime Library Reference and found nothing that matched.

Now most people would hit the internet and do a search for what they need. But for these kinds of functions, I always check the Snippets archive that I have first. A long time ago, there used to be a Snippets web site run by Bob Stout. Unfortunately, he died in 2011 and his web site disappeared a little while later. Luckily, the Way Back Machine has a full archive of his Snippets web site. A lot of people have posted/hosted his Snippets ‘97 archive but really everyone should be using the Snippets 2003 archive (latest release). I have the Snippets 2003 archive available to download here. The great feature of Bob Stout’s Snippets archive is that he licensed all code as public domain. Over the years, I have used many functions from Bob Stout’s Snippets archive and it has been truly helpful.

In the Snippets archive, there is an important file that describes each program/function called ‘snippets.ndx’. I did a quick search of the file and found the perfect function that matched my needs called memmem(). I copied the function to my program, tested it on Windows and it worked perfectly.

Life was great then I went to do a build on Linux and got the follow error:

error: conflicting types for ‘memmem’
void *memmem(const void *buf, const void *pattern, size_t buflen, size_t len)

I immediately shock my head and said WTF! I did “man memmem” command and sure enough, there is a memmem() function on Linux that does what I want. The parameter list is different but really it is just the order of the parameters.

I then did some internet searches and noticed a lot of people were doing searches for “memmem on Windows”. So, I got the bright idea of rearranging the parameter list for Snippets memmem() function (and use the same variable names as Linux) and post the updated code as public domain in Bob Stout’s name.

So here you go, a cross-platform version of memmem() function with defines to handle Linux:

#if !defined(__linux__)
/**
 * Function Name
 *  memmem
 *
 * Description
 *  Like strstr(), but for non-text buffers that are not NULL delimited.
 *
 *  public domain by Bob Stout
 *
 * Input parameters
 *  haystack    - pointer to the buffer to be searched
 *  haystacklen - length of the haystack buffer
 *  needle      - pointer to a buffer that will be searched for
 *  needlelen   - length of the needle buffer
 *
 * Return Value
 *  pointer to the memory address of the match or NULL.
 */
void *memmem(void *haystack, size_t haystacklen, void *needle, size_t needlelen)
{
   /* --------------------------------------------
    * Variable declarations.
    * --------------------------------------------
    */
   char *bf = (char*) haystack, *pt = (char*) needle, *p = bf;

   /* --------------------------------------------
    * Code section
    * --------------------------------------------
    */
   while (needlelen <= (haystacklen - (p - bf)))
   {
      if (NULL != (p = memchr(p, (int)(*pt), haystacklen - (p - bf))))
      {
         if (0 == memcmp(p, needle, needlelen))
            return p;
         else
            ++p;
      }
      else
         break;
   }

   return NULL;
}
#endif

Regards,
Roger Lacroix
Capitalware Inc.

This entry was posted in C, HPE NonStop, IBM i (OS/400), Linux, macOS (Mac OS X), Open Source, Programming, Unix, Windows, z/OS.

Comments are closed.