/* Shao Miller, 2012 */

#include <stdio.h>
#include <stdlib.h>

void * pmemcpy(void * s1, const void * s2, size_t n);
void * pmemmove(void * s1, const void * s2, size_t n);

int main(void) {
    char test1[] = "0123456789";
    char test2[] = "ABCDEFGHIJ";
    char * t1;
    char * t2;

    t1 = pmemmove(test1, test1 + 5, 5);
    t2 = pmemmove(test2 + 5, test2, 5);
    (void) t2;

    printf("%s\n%s\n", t1, test2);

    return EXIT_SUCCESS;
  }

void * pmemcpy(void * s1, const void * s2, size_t n) {
    unsigned char * dest;
    const unsigned char * src;

    if (!s1 || !s2 || !n)
      return s1;

    dest = s1;
    src = s2;

    while (n--)
      *dest++ = *src++;

    return s1;
  }

/* Portability wins over performance, here */
void * pmemmove(void * s1, const void * s2, size_t n) {
    unsigned char * dest;
    const unsigned char * src;
    const unsigned char * src_end;

    if (!s1 || !s2 || !n || s1 == s2)
      return s1;

    dest = s1;
    src = s2;

    /* The only interesting case is where src < dest with overlap */
    for (src_end = src + n; src < src_end; ++src) {
        if (src == dest)
          break;
      }

    /* Is src > dest or non-overlapping? */
    if (src == src_end)
      return pmemcpy(s1, s2, n);

    /* Otherwise, src < dest with overlap */
    dest += n;
    src = src_end;

    while (n--)
      *dest-- = *src--;

    return s1;
  }
