327 lines
9.9 KiB
C
327 lines
9.9 KiB
C
/****************************************************************************
|
|
* libs/libc/string/lib_memmem.c
|
|
*
|
|
* The MIT License (MIT)
|
|
*
|
|
* Copyright (c) 2014-2015 Tal Einat
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
* to deal in the Software without restriction, including without limitation
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
* DEALINGS IN THE SOFTWARE.
|
|
*
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Included Files
|
|
****************************************************************************/
|
|
|
|
#include <string.h>
|
|
|
|
/****************************************************************************
|
|
* Pre-processor Definitions
|
|
****************************************************************************/
|
|
|
|
#ifdef CONFIG_ALLOW_MIT_COMPONENTS
|
|
#define LONG_INT_N_BYTES sizeof(long)
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
* Public Functions
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Name: memmem
|
|
*
|
|
* Description:
|
|
* The memmem() function finds the start of the first occurrence of the
|
|
* substring needle of length needlelen in the memory area haystack of
|
|
* length haystacklen.
|
|
*
|
|
* Returned Value:
|
|
* The memmem() function returns a pointer to the beginning of the
|
|
* substring, or NULL if the substring is not found.
|
|
*
|
|
****************************************************************************/
|
|
|
|
#undef memmem /* See mm/README.txt */
|
|
FAR void *memmem(FAR const void *haystack, size_t haystacklen,
|
|
FAR const void *needle, size_t needlelen)
|
|
{
|
|
#ifdef CONFIG_ALLOW_MIT_COMPONENTS
|
|
FAR const unsigned char *needle_ptr;
|
|
FAR const unsigned char *haystack_ptr;
|
|
int sums_diff;
|
|
size_t compare_len;
|
|
unsigned long last_needle_chars;
|
|
unsigned long last_haystack_chars;
|
|
unsigned int i;
|
|
|
|
switch (needlelen)
|
|
{
|
|
case (0):
|
|
|
|
/* empty needle */
|
|
|
|
return (FAR void *)haystack;
|
|
break;
|
|
case (1):
|
|
|
|
/* special case for single-character needles */
|
|
|
|
return memchr(haystack,
|
|
*((FAR unsigned char *)needle), haystacklen);
|
|
break;
|
|
}
|
|
|
|
/* start searching through haystack only from the first occurence of
|
|
* the first character of needle.
|
|
*/
|
|
|
|
haystack_ptr = (FAR const unsigned char *)memchr(haystack,
|
|
*((FAR const unsigned char *)needle), haystacklen);
|
|
if (!haystack_ptr)
|
|
{
|
|
/* the first character of needle isn't in haystack */
|
|
|
|
return NULL;
|
|
}
|
|
|
|
haystacklen -= (haystack_ptr - (FAR const unsigned char *)haystack);
|
|
if (haystacklen < needlelen)
|
|
{
|
|
/* the remaining haystack is smaller than needle */
|
|
|
|
return NULL;
|
|
}
|
|
|
|
haystack = (FAR void *)haystack_ptr;
|
|
|
|
if (needlelen > LONG_INT_N_BYTES + 1)
|
|
{
|
|
needle_ptr = (FAR const unsigned char *)needle;
|
|
sums_diff = 0;
|
|
for (i = needlelen - LONG_INT_N_BYTES; i > 0; --i)
|
|
{
|
|
sums_diff -= *needle_ptr++;
|
|
sums_diff += *haystack_ptr++;
|
|
}
|
|
|
|
last_needle_chars = 0;
|
|
last_haystack_chars = 0;
|
|
for (i = LONG_INT_N_BYTES; i > 0; --i)
|
|
{
|
|
last_needle_chars <<= 8;
|
|
last_needle_chars ^= *needle_ptr;
|
|
last_haystack_chars <<= 8;
|
|
last_haystack_chars ^= *haystack_ptr;
|
|
sums_diff -= *needle_ptr++;
|
|
sums_diff += *haystack_ptr++;
|
|
}
|
|
|
|
/* we will call memcmp() only once we know that the sums are equal
|
|
* and that LONG_INT_N_BYTES last chars are equal, so it will be
|
|
* enough to compare all but the last LONG_INT_N_BYTES + 1
|
|
* characters.
|
|
*/
|
|
|
|
compare_len = needlelen - (LONG_INT_N_BYTES + 1);
|
|
|
|
/* At this point:
|
|
* needle is at least two characters long
|
|
* haystack is at least needlelen characters long (also at least two)
|
|
* the first characters of needle and haystack are identical
|
|
*/
|
|
|
|
if (sums_diff == 0
|
|
&& last_haystack_chars == last_needle_chars
|
|
&& memcmp(haystack, needle, compare_len) == 0)
|
|
{
|
|
return (FAR void *)haystack;
|
|
}
|
|
|
|
/* iterate through the remainder of haystack, updating the sums'
|
|
* differenceand checking for identity whenever the difference
|
|
* is zero.
|
|
*/
|
|
|
|
for (i = haystacklen - needlelen; i > 0; --i)
|
|
{
|
|
last_haystack_chars <<= 8;
|
|
last_haystack_chars ^= *haystack_ptr;
|
|
sums_diff -= *(FAR const unsigned char *)haystack++;
|
|
sums_diff += *haystack_ptr++;
|
|
/* if sums_diff == 0, we know that the sums are equal, so it is
|
|
* enough to compare all but the last characters.
|
|
*/
|
|
|
|
if (sums_diff == 0
|
|
&& last_haystack_chars == last_needle_chars
|
|
&& memcmp(haystack, needle, compare_len) == 0)
|
|
{
|
|
return (FAR void *)haystack;
|
|
}
|
|
}
|
|
}
|
|
else if (needlelen < LONG_INT_N_BYTES)
|
|
{
|
|
needle_ptr = (FAR const unsigned char *)needle;
|
|
sums_diff = 0;
|
|
for (i = needlelen; i > 0; --i)
|
|
{
|
|
sums_diff -= *needle_ptr++;
|
|
sums_diff += *haystack_ptr++;
|
|
}
|
|
|
|
/* we will call memcmp() only once we know that the sums are equal,
|
|
* so it will be enough to compare all but the last characters.
|
|
*/
|
|
|
|
compare_len = needlelen - 1;
|
|
|
|
/* At this point:
|
|
* needle is at least two characters long
|
|
* haystack is at least needlelen characters long (also at least two)
|
|
* the first characters of needle and haystack are identical
|
|
*/
|
|
|
|
if (sums_diff == 0
|
|
&& memcmp(haystack, needle, compare_len) == 0)
|
|
{
|
|
return (FAR void *)haystack;
|
|
}
|
|
|
|
/* iterate through the remainder of haystack, updating the sums'
|
|
* difference and checking for identity whenever the difference
|
|
* is zero.
|
|
*/
|
|
|
|
for (i = haystacklen - needlelen; i > 0; --i)
|
|
{
|
|
sums_diff -= *(FAR const unsigned char *)haystack++;
|
|
sums_diff += *haystack_ptr++;
|
|
/* if sums_diff == 0, we know that the sums are equal, so it is
|
|
* enough to compare all but the last characters.
|
|
*/
|
|
|
|
if (sums_diff == 0
|
|
&& memcmp(haystack, needle, compare_len) == 0)
|
|
{
|
|
return (FAR void *)haystack;
|
|
}
|
|
}
|
|
}
|
|
else if (needlelen == LONG_INT_N_BYTES)
|
|
{
|
|
needle_ptr = (FAR const unsigned char *)needle;
|
|
last_needle_chars = 0;
|
|
last_haystack_chars = 0;
|
|
for (i = needlelen; i > 0; --i)
|
|
{
|
|
last_needle_chars <<= 8;
|
|
last_needle_chars ^= *needle_ptr++;
|
|
last_haystack_chars <<= 8;
|
|
last_haystack_chars ^= *haystack_ptr++;
|
|
}
|
|
|
|
if (last_haystack_chars == last_needle_chars)
|
|
{
|
|
return (FAR void *)haystack;
|
|
}
|
|
|
|
/* iterate through the remainder of haystack, updating the last char
|
|
* data and checking for equality.
|
|
*/
|
|
|
|
for (i = haystacklen - needlelen; i > 0; --i)
|
|
{
|
|
last_haystack_chars <<= 8;
|
|
last_haystack_chars ^= *haystack_ptr++;
|
|
if (last_haystack_chars == last_needle_chars)
|
|
{
|
|
return (FAR void *)(haystack_ptr - needlelen);
|
|
}
|
|
}
|
|
}
|
|
else /* needlelen == LONG_INT_N_BYTES + 1 */
|
|
{
|
|
needle_ptr = (FAR const unsigned char *)needle;
|
|
last_needle_chars = 0;
|
|
last_haystack_chars = 0;
|
|
for (i = LONG_INT_N_BYTES; i > 0; --i)
|
|
{
|
|
last_needle_chars <<= 8;
|
|
last_needle_chars ^= *needle_ptr++;
|
|
last_haystack_chars <<= 8;
|
|
last_haystack_chars ^= *haystack_ptr++;
|
|
}
|
|
|
|
unsigned char last_needle_char =
|
|
*(((FAR const unsigned char *)needle) + LONG_INT_N_BYTES);
|
|
|
|
if (last_haystack_chars == last_needle_chars
|
|
&& *haystack_ptr == last_needle_char)
|
|
{
|
|
return (FAR void *)haystack;
|
|
}
|
|
|
|
/* iterate through the remainder of haystack, updating the last char
|
|
* data and checking for equality.
|
|
*/
|
|
|
|
for (i = haystacklen - needlelen; i > 0; --i)
|
|
{
|
|
last_haystack_chars <<= 8;
|
|
last_haystack_chars ^= *haystack_ptr++;
|
|
if (last_haystack_chars == last_needle_chars
|
|
&& *haystack_ptr == last_needle_char)
|
|
{
|
|
return (FAR void *)(haystack_ptr - (needlelen - 1));
|
|
}
|
|
}
|
|
}
|
|
#else
|
|
FAR const unsigned char *h = haystack;
|
|
FAR const unsigned char *n = needle;
|
|
size_t i;
|
|
size_t y;
|
|
|
|
if (needlelen == 0)
|
|
{
|
|
return (FAR void *)haystack;
|
|
}
|
|
|
|
if (needlelen > haystacklen)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
for (i = 0; i <= haystacklen - needlelen; i++)
|
|
{
|
|
y = 0;
|
|
while (h[i + y] == n[y])
|
|
{
|
|
if (++y == needlelen)
|
|
{
|
|
return (FAR void *)(h + i);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
return NULL;
|
|
}
|