libc/memmem:porting open source memmem to Nuttx.

Signed-off-by: yangguangcai <yangguangcai@xiaomi.com>
This commit is contained in:
yangguangcai
2024-02-05 22:05:28 +08:00
committed by Xiang Xiao
parent 15fa55f234
commit 5de562347d
3 changed files with 315 additions and 13 deletions

View File

@@ -6333,6 +6333,7 @@ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
libs/libc/string/lib_memmem.c
libs/libc/string/lib_strstr.c
===============================
The MIT License (MIT)

View File

@@ -1,22 +1,27 @@
/****************************************************************************
* libs/libc/string/lib_memmem.c
*
* SPDX-License-Identifier: Apache-2.0
* The MIT License (MIT)
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
* Copyright (c) 2014-2015 Tal Einat
*
* http://www.apache.org/licenses/LICENSE-2.0
* 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:
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
* 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.
*
****************************************************************************/
@@ -26,6 +31,14 @@
#include <string.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#ifdef CONFIG_ALLOW_MIT_COMPONENTS
#define LONG_INT_N_BYTES sizeof(long)
#endif
/****************************************************************************
* Public Functions
****************************************************************************/
@@ -48,6 +61,239 @@
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;
@@ -74,6 +320,7 @@ FAR void *memmem(FAR const void *haystack, size_t haystacklen,
}
}
}
#endif
return NULL;
}

View File

@@ -40,7 +40,9 @@
* Pre-processor Definitions
****************************************************************************/
#ifdef CONFIG_ALLOW_MIT_COMPONENTS
#define LONG_INT_N_BYTES sizeof(long)
#endif
/****************************************************************************
* Public Functions
@@ -53,6 +55,7 @@
#undef strstr /* See mm/README.txt */
FAR char *strstr(FAR const char *haystack, FAR const char *needle)
{
#ifdef CONFIG_ALLOW_MIT_COMPONENTS
FAR const unsigned char *needle_cmp_end;
FAR const unsigned char *i_haystack;
const char needle_first = *needle;
@@ -226,6 +229,57 @@ FAR char *strstr(FAR const char *haystack, FAR const char *needle)
}
}
}
#else
FAR const char *candidate; /* Candidate in haystack with matching start character */
char ch; /* First character of the substring */
size_t len; /* The length of the substring */
/* Special case the empty substring */
len = strlen(needle);
ch = *needle;
if (!ch)
{
/* We'll say that an empty substring matches at the beginning of
* the string
*/
return (FAR char *)haystack;
}
/* Search for the substring */
candidate = haystack;
for (; ; )
{
/* strchr() will return a pointer to the next occurrence of the
* character ch in the string
*/
candidate = strchr(candidate, ch);
if (!candidate || strlen(candidate) < len)
{
/* First character of the substring does not appear in the string
* or the remainder of the string is not long enough to contain the
* substring.
*/
return NULL;
}
/* Check if this is the beginning of a matching substring */
if (strncmp(candidate, needle, len) == 0)
{
return (FAR char *)candidate;
}
/* No, find the next candidate after this one */
candidate++;
}
#endif
return NULL;
}