#ifndef _STRING_H
#define _STRING_H

#include <stdc_common.h>


void *memmove(void *s1, const void *s2, size_t n) {
	if (s1 < s2) return memcpy(s1, s2, n); // our memcpy does a forwards copy
	// backwards copy
	char *p = (char*)s1 + n, *q = (char*)s2 + n;
	while (p > s1)
		*--p = *--q;
	return s1;
}

char *strcpy(char *s1, const char *s2) {
	char *p = s1 - 1, *q = s2 - 1;
	while ((*++p = *++q));
	return s1;
}

char *strncpy(char *s1, const char *s2, size_t n) {
	char *p = s1 - 1, *q = s2 - 1;
	size_t i;
	for (i = 0; i < n; ++i)
		if (!(*++p = *++q))
			break;
	for (; i < n; ++i)
		*++p = 0;
	return s1;
}

char *strcat(char *s1, const char *s2) {
	return strcpy(s1 + strlen(s1), s2);
}

char *strncat(char *s1, const char *s2, size_t n) {
	// oddly, not equivalent to strncpy(s1 + strlen(s1), s2, n)
	char *p = s1 + strlen(s1) - 1, *q = s2 - 1;
	size_t i;
	for (i = 0; i < n; ++i)
		if (!(*++p = *++q))
			break;
	*++p = 0;
	return s1;
}

int memcmp(const void *s1, const void *s2, size_t n) {
	char *p = s1, *q = s2;
	size_t i;
	for (i = 0; i < n; ++i, ++p, ++q) {
		if (*p > *q)
			return 1;
		if (*p < *q)
			return -1;
	}
	return 0;
}

int strcmp(const char *s1, const char *s2) {
	char *p = s1, *q = s2;
	for (; ; ++p, ++q) {
		if (*p > *q)
			return 1;
		if (*p < *q)
			return -1;
		if (!*p) break;
	}
	return 0;
}

int strcoll(const char *s1, const char *s2) {
	// we only support the C locale
	return strcmp(s1, s2);
}

int strncmp(const char *s1, const char *s2, size_t n) {
	char *p = s1, *q = s2;
	size_t i;
	for (i = 0; i < n; ++i, ++p, ++q) {
		if (*p > *q)
			return 1;
		if (*p < *q)
			return -1;
		if (!*p) break;
	}
	return 0;
}

size_t strxfrm(char *s1, const char *s2, size_t n) {
	// we only support the C locale
	size_t l = strlen(s2);
	if (l >= n) return l;
	strcpy(s1, s2);
	return l;
}

void *memchr(const void *s, int c, size_t n) {
	char *p = s, *end = p + n;
	while (p < end) {
		if ((unsigned char)*p == c)
			return p;
		++p;
	}
	return NULL;
}

char *strchr(const char *s, int c) {
	return memchr(s, c, strlen(s)+1);
}


size_t strcspn(const char *s1, const char *s2) {
	const char *p, *q;
	for (p = s1; *p; ++p) {
		for (q = s2; *q; ++q) {
			if (*p == *q)
				goto ret;
		}
	}
	ret:
	return p - s1;
}

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

char *strrchr(const char *s, int c) {
	char *p;
	for (p = s + strlen(s); p >= s; --p) {
		if (*p == c)
			return p;
	}
	return NULL;
}

size_t strspn(const char *s1, const char *s2) {
	const char *p, *q;
	for (p = s1; *p; ++p) {
		for (q = s2; *q; ++q) {
			if (*p == *q) break;
		}
		if (!*q) break;
	}
	return p - s1;
}

char *strstr(const char *s1, const char *s2) {
	char *p;
	size_t l = strlen(s2);
	for (p = s1; *p; ++p) {
		if (memcmp(p, s2, l) == 0)
			return p;
	}
	return NULL;
}

char *strtok(char *s1, const char *s2) {
	static char *str;
	if (s1) str = s1;
	if (!str) return NULL;
	char *p = str + strspn(str, s2);
	if (!*p) {
		str = NULL;
		return NULL;
	}
	char *q = strpbrk(p, s2);
	if (q) {
		*q = 0;
		str = q + 1;
	} else {
		str = NULL;
	}
	return p;
}

#endif // _STRING_H
