#include "str.h"

/* mem_cpy - copy memory area */
void *mem_cpy(void *dst, const void *src, size_t n) {
 register const unsigned char *s=src;
 register unsigned char *d=dst;
 while (n--) { *d = *s; ++d; ++s; }
 return dst;
}

/* mem_set - fill memory with a constant byte */
void *mem_set(void *dst, unsigned char c, size_t n) {
 register unsigned char *tmp=dst;
 while (n--) *tmp++ = c;
 return dst;
}

/* mem_cmp - compare memory areas */
size_t mem_cmp(const void *s1, const void *s2, size_t n) {
 register const char *d=s1, *s=s2;
 register size_t r;
 while (n--) {
  if ((r=(*d - *s))) return r;
  ++d; ++s;
 }
 return 0;
}

/* mem_move - copy memory area */
void *mem_move(void *dst, const void *src, size_t n) {
 register const char *s=src;
 register char *d=dst;
 if (src!=dst) {
  if (src>dst) {
   while (n--) *d++ = *s++;
  } else {
   d+=n-1; s+=n-1;
   while (n--) *d-- = *s--;
  }
 }
 return dst;
}

/* str_cpy - copy a string */
size_t str_cpy(unsigned char *dst, const unsigned char *src) {
 register size_t i;
 for (i=1; *src; i++) *dst++ = *src++;
 *dst=0;
 return i;
}

/* str_ncpy - copy n bytes of a string */
size_t str_ncpy(unsigned char *dst, const unsigned char *src, size_t n) {
 register size_t i;
 for (i=1; i<n && *src; i++) *dst++ = *src++;
 *dst=0;
 return i;
}

/* str_ncmp - compare two strings */
size_t str_ncmp(const unsigned char *s1, const unsigned char *s2, size_t n) {
 return mem_cmp(s1, s2, n);
}

/* str_cmp - compare two strings */
size_t str_cmp(const unsigned char *s1, const unsigned char *s2) {
 register unsigned char x;
 for (;;) {
  x = *s1; if (x!=*s2) break; if (!x) break; ++s1; ++s2;
 }
 return x - *s2;
}

/* str_len - determine the length of a fixed-size string */
size_t str_len(register const unsigned char *s) {
 register size_t i;
 if (!s) return 0;
 for (i=0; *s; ++s) ++i;
 return i;
}

/* str_cat - concatenate two strings */
unsigned char *str_cat(unsigned char *dst, const unsigned char *src) {
 register unsigned char *d=dst;
 dst+=str_len(dst); /* goto the end of it */
 while ((*dst = *src)) { ++dst; ++src; } /* append src2dst */
 *dst=0; /* terminate the str */
 return d;
}

/* str_dup - duplicate a string */
unsigned char *str_dup(const unsigned char *str) {
 unsigned char *tmp;
 if (!(tmp=mallocn(unsigned char, str_len(str)+1))) return 0;
 str_cpy(tmp, str);
 return tmp;
}

/* str_chr - search charcter in string */
unsigned char *str_chr(const unsigned char *str, unsigned char c) {
 for (;;) {
  if (*str==c) break;
  if (!*str) return 0;
  str++;
 }
 return (unsigned char*)str;
}

/* str_rchr - search charcter in string */
unsigned char *str_rchr(const unsigned char *str, unsigned char c) {
 register const unsigned char *l=0;
 for (;;) {
  if (*str==c) l=str;
  if (!*str) return (unsigned char*)l;
  str++;
 }
 return (unsigned char*)l;
}

/* str_str - locate a substring */
unsigned char *str_str(const unsigned char *haystack, const unsigned char *needle) {
 size_t nl=str_len(needle), hl=str_len(haystack);
 register size_t i;
 if (nl>hl) return 0;
 for (i=hl-nl+1; i; --i) {
  if (!mem_cmp(haystack, needle, nl))
   return (unsigned char*)haystack;
  ++haystack;
 }
 return (unsigned char*)0;
}

/* str_concat - string1..n to one string */
unsigned char *str_concat(const char *first, ...) {
 register char *data, *result;
 size_t len;
 va_list ap;

 if (!first) return 0;
 len=str_len((unsigned char *)first)+1;
 va_start (ap, first);
 while((data=va_arg(ap, char*))) len+=str_len((unsigned char *)data);
 result=xmalloc(len);
 va_end(ap);

 va_start(ap, first);
 str_cpy((unsigned char *)result, (unsigned char *)first);
 while((data=va_arg(ap, char*))) str_cat((unsigned char *)result,
  (unsigned char *)data);
 va_end(ap);
 return (unsigned char *)result;
}

/* str_add - add to **dst some new string */
unsigned char *str_add(unsigned char **dst, const unsigned char *append) {
 unsigned char *p;
 if (!append) return *dst;
 p=(unsigned char*)xrealloc((void*)*dst, str_len(append)+str_len(*dst)+1);
 if (!p) return *dst; /* failed: just return the old ptr, whatever it was */
 str_cat(p, append);
 return *dst=p;
}

/* str_split - split *str into n strings, that are seperated by c */
unsigned char **str_split(unsigned char *buf, unsigned char c, size_t *len) {
 size_t n=1;
 unsigned char **v=0, **w, *s;
 for (s=buf; *s; s++) if (*s==c) n++; /* step 1: count tokens */
 v=mallocn(unsigned char*, n); /* step 2: allocate space for pointers */
 if (!v) return 0;
 w=v; *w++=buf; /* set pointer to the pointer of our chars */
 for (s=buf;;s++) {
  while (*s && *s!=c) s++;
  if (*s==0) break;
  if (*s==c) { *s=0; *w++=s+1; } /* null terminate */
 }
 *len=w-v; /* how much splits? */
 return v; /* the beginning of them */
}
