| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #include "build-defs.h" | ||
| 2 | #include <string.h> | ||
| 3 | #include "xmemmem.h" | ||
| 4 | #include "debug.h" | ||
| 5 | |||
| 6 | 54 | void *xmemmem(const void *haystack, size_t hlen, const void *needle, size_t nlen) | |
| 7 | { | ||
| 8 | 54 | BUG_ON(nlen == 0); | |
| 9 | |||
| 10 | #if HAVE_MEMMEM | ||
| 11 | 54 | return memmem(haystack, hlen, needle, nlen); | |
| 12 | #endif | ||
| 13 | |||
| 14 | // Note: this fallback implementation isn't well suited to general | ||
| 15 | // purpose use and can exhibit poor performance under certain inputs. | ||
| 16 | // A library-quality memmem(3) isn't a trivial thing to implement, | ||
| 17 | // but fortunately almost every modern platform already has one in | ||
| 18 | // libc and it was added to the POSIX base spec in issue 8. Therefore, | ||
| 19 | // this code isn't likely to be used, and even when it is, it should | ||
| 20 | // be acceptable for the uses in this codebase. | ||
| 21 | |||
| 22 | const char *start = haystack; | ||
| 23 | int first_char = ((const unsigned char*)needle)[0]; | ||
| 24 | if (nlen == 1) { | ||
| 25 | return memchr(start, first_char, hlen); | ||
| 26 | } | ||
| 27 | |||
| 28 | while (1) { | ||
| 29 | char *ptr = memchr(start, first_char, hlen); | ||
| 30 | if (!ptr) { | ||
| 31 | return NULL; | ||
| 32 | } | ||
| 33 | size_t skip = (size_t)(ptr - start); | ||
| 34 | if (skip + nlen > hlen) { | ||
| 35 | return NULL; | ||
| 36 | } | ||
| 37 | if (memcmp(ptr, needle, nlen) == 0) { | ||
| 38 | return ptr; | ||
| 39 | } | ||
| 40 | start = ptr + 1; | ||
| 41 | hlen -= skip + 1; | ||
| 42 | } | ||
| 43 | |||
| 44 | BUG("unexpected loop break"); | ||
| 45 | return NULL; | ||
| 46 | } | ||
| 47 |