forked from KolibriOS/kolibrios
103 lines
3.0 KiB
C
103 lines
3.0 KiB
C
|
/* Byte-wise substring search, using the Two-Way algorithm.
|
||
|
* Copyright (C) 2008 Eric Blake
|
||
|
* Permission to use, copy, modify, and distribute this software
|
||
|
* is freely granted, provided that this notice is preserved.
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
FUNCTION
|
||
|
<<memmem>>---find memory segment
|
||
|
|
||
|
INDEX
|
||
|
memmem
|
||
|
|
||
|
ANSI_SYNOPSIS
|
||
|
#include <string.h>
|
||
|
char *memmem(const void *<[s1]>, size_t <[l1]>, const void *<[s2]>,
|
||
|
size_t <[l2]>);
|
||
|
|
||
|
DESCRIPTION
|
||
|
|
||
|
Locates the first occurrence in the memory region pointed to
|
||
|
by <[s1]> with length <[l1]> of the sequence of bytes pointed
|
||
|
to by <[s2]> of length <[l2]>. If you already know the
|
||
|
lengths of your haystack and needle, <<memmem>> can be much
|
||
|
faster than <<strstr>>.
|
||
|
|
||
|
RETURNS
|
||
|
Returns a pointer to the located segment, or a null pointer if
|
||
|
<[s2]> is not found. If <[l2]> is 0, <[s1]> is returned.
|
||
|
|
||
|
PORTABILITY
|
||
|
<<memmem>> is a newlib extension.
|
||
|
|
||
|
<<memmem>> requires no supporting OS subroutines.
|
||
|
|
||
|
QUICKREF
|
||
|
memmem pure
|
||
|
*/
|
||
|
|
||
|
#include <string.h>
|
||
|
|
||
|
#if !defined(PREFER_SIZE_OVER_SPEED) && !defined(__OPTIMIZE_SIZE__)
|
||
|
# define RETURN_TYPE void *
|
||
|
# define AVAILABLE(h, h_l, j, n_l) ((j) <= (h_l) - (n_l))
|
||
|
# include "str-two-way.h"
|
||
|
#endif
|
||
|
|
||
|
void *
|
||
|
_DEFUN (memmem, (haystack_start, haystack_len, needle_start, needle_len),
|
||
|
const void *haystack_start _AND
|
||
|
size_t haystack_len _AND
|
||
|
const void *needle_start _AND
|
||
|
size_t needle_len)
|
||
|
{
|
||
|
/* Abstract memory is considered to be an array of 'unsigned char' values,
|
||
|
not an array of 'char' values. See ISO C 99 section 6.2.6.1. */
|
||
|
const unsigned char *haystack = (const unsigned char *) haystack_start;
|
||
|
const unsigned char *needle = (const unsigned char *) needle_start;
|
||
|
|
||
|
if (needle_len == 0)
|
||
|
/* The first occurrence of the empty string is deemed to occur at
|
||
|
the beginning of the string. */
|
||
|
return (void *) haystack;
|
||
|
|
||
|
#if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__)
|
||
|
|
||
|
/* Less code size, but quadratic performance in the worst case. */
|
||
|
while (needle_len <= haystack_len)
|
||
|
{
|
||
|
if (!memcmp (haystack, needle, needle_len))
|
||
|
return (void *) haystack;
|
||
|
haystack++;
|
||
|
haystack_len--;
|
||
|
}
|
||
|
return NULL;
|
||
|
|
||
|
#else /* compilation for speed */
|
||
|
|
||
|
/* Larger code size, but guaranteed linear performance. */
|
||
|
|
||
|
/* Sanity check, otherwise the loop might search through the whole
|
||
|
memory. */
|
||
|
if (haystack_len < needle_len)
|
||
|
return NULL;
|
||
|
|
||
|
/* Use optimizations in memchr when possible, to reduce the search
|
||
|
size of haystack using a linear algorithm with a smaller
|
||
|
coefficient. However, avoid memchr for long needles, since we
|
||
|
can often achieve sublinear performance. */
|
||
|
if (needle_len < LONG_NEEDLE_THRESHOLD)
|
||
|
{
|
||
|
haystack = memchr (haystack, *needle, haystack_len);
|
||
|
if (!haystack || needle_len == 1)
|
||
|
return (void *) haystack;
|
||
|
haystack_len -= haystack - (const unsigned char *) haystack_start;
|
||
|
if (haystack_len < needle_len)
|
||
|
return NULL;
|
||
|
return two_way_short_needle (haystack, haystack_len, needle, needle_len);
|
||
|
}
|
||
|
return two_way_long_needle (haystack, haystack_len, needle, needle_len);
|
||
|
#endif /* compilation for speed */
|
||
|
}
|