#include "app.h"
/****************************************************************************
 *	clippce.c
 ****************************************************************************/
static char* strstr_sub(const char* s1, const char* s2, int (*fn)(const char*, const char*, size_t));
char* strstr(const char* s1, const char* s2) {
	return strstr_sub(s1, s2, strncmp);
}
char* strcasestr(const char* s1, const char* s2) {
	return strstr_sub(s1, s2, strncasecmp);
}
static char* strstr_sub(const char* s1, const char* s2, int (*fn)(const char*, const char*, size_t)) {
	/* 部分文字列の文字数を求める。(s2="")でも構わない。 */
	int n = strlen(s2);
	/* 文字列の先頭から検索を開始する。
	 * - (s1="")の場合も、一回目のループは実行する。
	 *   (s2="")の場合は、s1の内容にかかわらず((s1="")であってもなくても)常に一致するからです。 */
	do {
		/* 文字列の現在位置から、部分文字列の文字数分比較を行い、一致したら現在位置を返す。
		 * - (s2="")だった場合、s1の内容にかかわらず((s1="")であってもなくても)、一致する。
		 * - (s1="")だった場合、(s2="")でなければ、一致しない。 */
		if(!(*fn)(s1, s2, n)) { return (char*)s1; }
	/* 文字列の終端でなければ、位置を次へ進める。
	 * - (s1="")だった場合は、一回目で抜けることになる。 */
	} while(*s1++);
	/* 文字列の終端における比較でも一致しなければ、NULLを返す。 */
	return NULL;
}
/*--------------------------------------------------------------------------*/
size_t strlen(const char* string) {
	return strnlen(string, SIZE_MAX);
}
/* strnlen()関数は、stringが指す文字列の長さを、バイト数で返す。
 * 長さには、終端の'\0'は含まない。
 * 長さは最大で、nまでである。
 * strnlen()関数は、stringの最初のnバイトのみを検査し、string+nより先を検査することはない。
 */
size_t strnlen(const char* string, size_t n) {
	size_t len = 0;
	while((n--) && (*string++)) {
		len++;
	}
	return len;
}
/*--------------------------------------------------------------------------*/
//char* strdup(const char* string) {						//⇒Boehm GC
//	return strndup(string, SIZE_MAX);
//}
///* strndup()関数は、strdup()と同様であるが、最大でnバイトだけを複製する。
// * stringがnよりも長い場合は、nバイトだけを複製し、終端の'\0'を追加する。
// */
//char* strndup(const char* string, size_t n) {					//⇒Boehm GC
//	size_t len = strnlen(string, n);
//	char* p =  malloc(len + 1/*終端の'\0'の分、忘れずに!*/);
//	if(p != NULL) {
//		p[len] = '\0';
//		memcpy(p, string, len);
//	}
//	return p;
//}
/*--------------------------------------------------------------------------*/
int strcasecmp(const char* s1, const char* s2) {
	int c1, c2;
	do {
		c1 = tolower(*s1++ & 0xff);
		c2 = tolower(*s2++ & 0xff);
	} while(c1 != '\0' && c1 == c2);
	return c1 - c2;
}
int strncasecmp(const char* s1, const char* s2, size_t n) {
	int c1, c2;
	do {
		if(n-- == 0) return 0;
		c1 = tolower(*s1++ & 0xff);
		c2 = tolower(*s2++ & 0xff);
	} while(c1 != '\0' && c1 == c2);
	return c1 - c2;
}
/*--------------------------------------------------------------------------*/
char* strsep(char** stringp, const char* delim) {
	char* begin = *stringp;
	if(begin) {
		char* end = strpbrk(begin, delim);
		if(end) { *end++ = '\0'; }
		*stringp = end;
	}
	return begin;
}
char* strpbrk(const char* s, const char* accept) {
	const char* p;
	for(;;) {
		int c = *s++;
		if(!c) { return NULL; }
		p = accept;
		for(;;) {
			int t = *p++;
			if(!t) { break; }
			if(t == c) { return (char*)(s - 1); }
		}
	}
}
/*--------------------------------------------------------------------------*/
size_t strlcpy(char* dst, const char* src, size_t size) {
	size_t len = strlen(src);			//転送元の文字列の長さを求める。
	if(size--) {					//バッファサイズを1減らす。1減らす前のバッファサイズが0でなければ…
		if(size > len) { size = len; }		//転送する文字列の長さを求める。
		memcpy(dst, src, size);			//文字列を転送する。
		dst[size] = '\0';			//文字列をヌル終端する。
	}
	return len;					//転送元の文字列の長さを返す。
}
size_t strlcat(char* dst, const char* src, size_t size) {
	size_t dlen = strlen(dst);			//転送先の文字列の長さを求める。
	size_t slen = strlen(src);			//転送元の文字列の長さを求める。
	size_t tlen = dlen + slen;			//文字列の長さの合計を求める。
	if(size > dlen) {				//転送先の文字列がバッファ内でヌル終端されていたら…
		size -= dlen;				//(バッファ内に追加可能な文字数+1)を求める。
		if(slen >= size) { slen = size - 1; }	//追加する文字列の長さを求める。
		dst += dlen;				//文字列を追加する位置を求める。
		memcpy(dst, src, slen);			//文字列を追加する。
		dst[slen] = '\0';			//文字列をヌル終端する。
	}
	return tlen;					//文字列の長さの合計を返す。
}
/*--------------------------------------------------------------------------*/
int isblank(int c) {
	return (c == ' ') || (c == '\t');
}
/*--------------------------------------------------------------------------*/
size_t malloc_usable_size(void* ptr) {
#ifndef GC_H
	return ptr ? _msize(ptr) : 0;
#else //GC_H
	//Boehm GCを使用すると、malloc()はメモリブロックの途中(=管理情報の後)のポインタを返す。
	//GC_size()は、メモリブロックの途中が指定されても、メモリブロックの全体のサイズを返す。
	//malloc()が返したポインタ以降のサイズを得るには、以下のように計算しなくてはならない。(実験より推測)
	return ptr ? (GC_size(ptr) - ((int)ptr - (int)GC_base(ptr))) : 0;
#endif//GC_H
}
