/* CC0 (Public domain) - see LICENSE file for details */

#include "config.h"

#include <assert.h>
#include <string.h>
#include "mem.h"

#if !HAVE_MEMMEM
void *memmem(const void *haystack, size_t haystacklen,
         const void *needle, size_t needlelen)
{
    const char *p;

    if (needlelen > haystacklen)
        return NULL;

    p = haystack;

    for (p = haystack;
         (p + needlelen) <= ((const char *)haystack + haystacklen);
         p++)
        if (memcmp(p, needle, needlelen) == 0)
            return (void *)p;

    return NULL;
}
#endif

#if !HAVE_MEMRCHR
void *memrchr(const void *s, int c, size_t n)
{
    unsigned char *p = (unsigned char *)s;

    while (n) {
        if (p[n-1] == c)
            return p + n - 1;
        n--;
    }

    return NULL;
}
#endif

void *mempbrkm(const void *data_, size_t len, const void *accept_, size_t accept_len)
{
    const char *data = data_, *accept = accept_;
    size_t i, j;

    for (i = 0; i < len; i++)
        for (j = 0; j < accept_len; j++)
            if (accept[j] == data[i])
                return (void *)&data[i];
    return NULL;
}

void *memcchr(void const *data, int c, size_t data_len)
{
    char const *p = data;
    size_t i;

    for (i = 0; i < data_len; i++)
        if (p[i] != c)
            return (void *)&p[i];

    return NULL;
}

#define MEMSWAP_TMP_SIZE    256

void memswap(void *a, void *b, size_t n)
{
    char *ap = a;
    char *bp = b;
    char tmp[MEMSWAP_TMP_SIZE];

    assert(!memoverlaps(a, n, b, n));

    while (n) {
        size_t m = n > MEMSWAP_TMP_SIZE ? MEMSWAP_TMP_SIZE : n;

        memcpy(tmp, bp, m);
        memcpy(bp, ap, m);
        memcpy(ap, tmp, m);

        ap += m;
        bp += m;
        n -= m;
    }
}

bool memeqzero(const void *data, size_t length)
{
    const unsigned char *p = data;
    size_t len;

    /* Check first 16 bytes manually */
    for (len = 0; len < 16; len++) {
        if (!length)
            return true;
        if (*p)
            return false;
        p++;
        length--;
    }

    /* Now we know that's zero, memcmp with self. */
    return memcmp(data, p, length) == 0;
}

void memtaint(void *data, size_t len)
{
    /* Using 16 bytes is a bit quicker than 4 */
    const unsigned tainter[]
        = { 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef };
    char *p = data;

    while (len >= sizeof(tainter)) {
        memcpy(p, tainter, sizeof(tainter));
        p += sizeof(tainter);
        len -= sizeof(tainter);
    }
    memcpy(p, tainter, len);

#if HAVE_VALGRIND_MEMCHECK_H
    VALGRIND_MAKE_MEM_UNDEFINED(data, len);
#endif
}
