#include <stddef.h>
#include "chkr-string.h"

void
bcopy (const char *src, char *dest, int len)
{
  if (dest < src)
    while (len--)
      *dest++ = *src++;
  else
    {
      char *lasts = (char *)src + (len-1);
      char *lastd = dest + (len-1);
      while (len--)
        *(char *)lastd-- = *(char *)lasts--;
    }
}

void *
memcpy (void *o, const void *i, size_t len)
{
  bcopy (i, o, len);
  return o;
}

void *
memmove (void *s1, const void *s2, size_t n)
{
  bcopy (s2, s1, n);
  return s1;
}

void *
memchr (const void *src_void, int c, size_t length)
{
  const unsigned char *src = (const unsigned char *)src_void;
  
  if (length == 0)
    return NULL;
    
  while (length-- > 0)
  {
    if (*src == c)
     return (void *)src;
    src++;
  }
  return NULL;
}

int
memcmp (const void *str1, const void *str2, size_t count)
{
  register unsigned char *s1 = (unsigned char*)str1;
  register unsigned char *s2 = (unsigned char*)str2;
  int diff = 0;

  while (count-- > 0)
    {
      diff = *s1++ - *s2++;
      if (diff != 0)
	break;
    }
  return diff;
}

void *
memset (void * dest, int val, size_t len)
{
  register unsigned char *ptr = (unsigned char*)dest;
  while (len-- > 0)
    *ptr++ = val;
  return dest;
}

char *
strcat (char *dest, const char *src)
{
  register char *s1 = dest;
  register const char *s2 = src;
  char c;

  /* Find the end of the string.  */
  do
    c = *s1++;
  while (c != '\0');

  /* Make S1 point before the next character, so we can increment
     it while memory is read (wins on pipelined cpus).  */
  s1 -= 2;

  do
    {
      c = *s2++;
      *++s1 = c;
    }
  while (c != '\0');

  return dest;
}

int
strcmp (const char *p1, const char *p2)
{
  register const unsigned char *s1 = (const unsigned char *) p1;
  register const unsigned char *s2 = (const unsigned char *) p2;
  unsigned char c1, c2;

  do
    {
      c1 = (unsigned char) *s1++;
      c2 = (unsigned char) *s2++;
      if (c1 == '\0')
	return c1 - c2;
    }
  while (c1 == c2);

  return c1 - c2;
}

/* Copy SRC to DEST.  */
char *
strcpy (char *dest, const char *src)
{
  char c;
  char *s = (char *) src;
  const ptrdiff_t off = dest - src - 1;

  do
    {
      c = *s++;
      s[off] = c;
    }
  while (c != '\0');

  return dest;
}

char *
strncpy (char *dest, const char *src, size_t n)
{
  char c;
  char *s = (char *) src;
  const ptrdiff_t off = dest - src - 1;
  
  if (n == 0)
    return dest;
    
  do
    {
      c = *s++;
      s[off] = c;
      if (--n == 0)
        break;
    }
  while (c != '\0');

  if (n)
    memset (&s[off+1], 0, n);

  return dest;
}

char *
strchr (const char *s, int i)
{
  char c = (char) i;

  goto test;
  for (;;)
    {
      s++;
    test:
      if (*s == c)
	return (char *) s;
      if (*s == 0)
	return (char *) 0;
    }
}

int
strncmp (const char *s1, const char *s2, size_t n)
{
  unsigned char c1;
  unsigned char c2;
  
  if (n == 0)
    return 0;
    
  for (; n > 0; n--)
    {
      c1 = (unsigned char) *s1++;
      c2 = (unsigned char) *s2++;
      if (c1 == 0 || c1 != c2)
        return c1 - c2;
    }
    
  return c1 - c2;
}

size_t
strlen (const char *s)
{
  size_t len = 0;
  
  while (*s++)
    len++;
  return len;
}

#if 0
char *
strncat (char *s1, const char *s2, size_t n)
{
  char *s1_p = s1;
  
  while (*s1_p != 0)
    s1_p++;
  for (; n; n++)
    if(0 == (*s1_p++ = *s2++))
      return s1;
  *s1_p = 0;
  return s1;
}

size_t
strcspn (const char *s1, const char *s2)
{
  const char *p;

  for (p=s1; *p; p++)
    if (strchr (s2, *p))
      break;
  return p - s1;
}

char *
strpbrk (const char *s1, const char *s2)
{
  for (; *s1; s1++)
    if (strchr (s2, *s1))
      return (char *) s1;
  return NULL;
}

size_t 
strspn (const char *s1, const char *s2)
{
  const char *p;

  for (p=s1; *p; p++)
    if (!strchr (s2, *p))
      break;
  return p - s1;
}

char *
memmem (const char *haystack, int haystack_len,
	const char *needle, int needle_len)
{
  int i;

  for (i=0; i <= haystack_len - needle_len; i++)
    if (!memcmp (needle, &haystack[i], needle_len))
      return (char *) (&haystack[i]);
  return NULL;
}

char *
strstr (const char *haystack, const char *needle)
{
  return memmem (haystack, strlen (haystack), needle, strlen (needle));
}

char *
strtok (char *s1, const char *s2)
{
  static char *next = NULL;
  char *token_beg;
  char *token_end;
  
  if (s1 == NULL)
    s1 = next;

  token_beg = s1 + strspn(s1, s2);
  
  next = NULL;
  if (*s1 == 0)
    return NULL;
      
  token_end = strpbrk(token_beg, s2);
  if(token_end == NULL)
    return token_beg;
	     
  *token_end = 0;
  next = &token_end[1];
    
  return token_beg;
}
#endif
