/*$
mlk in apdtool
Copyright (c) 2020 Azel

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
$*/

/*****************************************
 * 標準関数
 *****************************************/

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

#include "mlk.h"


/**@ デバッグ用メッセージ出力
 * 
 * @d:標準エラー出力に出力する。\
 * 改行は行わない。 */

void mDebug(const char *format,...)
{
	va_list arg;

	va_start(arg, format);
	vfprintf(stderr, format, arg);
	va_end(arg);

	fflush(stderr);
}

/**@ エラー用メッセージ出力
 *
 * @d:標準エラー出力に出力する。\
 * 先頭に "[Error] " が付く。\
 * 改行は行わない。 */

void mError(const char *format,...)
{
	va_list arg;

	fputs("[Error] ", stderr);

	va_start(arg, format);
	vfprintf(stderr, format, arg);
	va_end(arg);

	fflush(stderr);
}

/**@ 警告用メッセージ出力
 *
 * @d:標準エラー出力に出力する。\
 * 先頭に "[Warning] " が付く。\
 * 改行は行わない。 */

void mWarning(const char *format,...)
{
	va_list arg;

	fputs("[Warning] ", stderr);

	va_start(arg, format);
	vfprintf(stderr, format, arg);
	va_end(arg);

	fflush(stderr);
}


//=============================
// メモリ関連 : 非デバッグ用
//=============================


/**@ メモリ解放 (非デバッグ)
 * 
 * @p:ptr NULL の場合は何もしない */

void mFree_r(void *ptr)
{
	if(ptr)
		free(ptr);
}

/**@ メモリ確保 (非デバッグ) */

void *mMalloc_r(mlksize size)
{
	return malloc(size);
}

/**@ メモリ確保してゼロクリア (非デバッグ) */

void *mMalloc0_r(mlksize size)
{
	return calloc(1, size);
}

/**@ メモリサイズ変更 (非デバッグ)
 *
 * @p:ptr NULL の場合、malloc と同じ
 * @r:新しく確保されたバッファのポインタ。\
 * ポインタが変わらない場合もある。\
 * NULL でエラー。その場合、元のメモリは変化しない。 */

void *mRealloc_r(void *ptr,mlksize size)
{
	return realloc(ptr, size);
}

/**@ アラインメントされたメモリ確保 (非デバッグ)
 *
 * @d:ポインタは mFree() で解放できる。
 * @p:size alignment の倍数である必要はない。
 * @p:alignment このバイト単位の位置に配置される。\
 * 2 のべき乗で、かつポインタのサイズ [sizeof(void*)] の倍数であること。\
 * \
 * 負の値で、mMalloc() と同じ。\
 * 0〜ポインタのサイズ以下の場合は、自動で最小値に調整される。 */

void *mMallocAlign_r(mlksize size,int alignment)
{
	void *ptr;

	if(alignment < 0)
		ptr = malloc(size);
	else
	{
		if(alignment < sizeof(void *))
			alignment = sizeof(void *);

		posix_memalign(&ptr, alignment, size);
	}

	return ptr;
}

/**@ 文字列複製 (非デバッグ)
 *
 * @p:str NULL の場合、NULL が返る */

char *mStrdup_r(const char *str)
{
	if(str)
		return strdup(str);
	else
		return NULL;
}

/**@ 文字列を指定長さ分だけ複製 (非デバッグ)
 *
 * @d:終端にはヌル文字が追加される
 * 
 * @p:str NULL の場合、NULL が返る
 * @p:len 負の値で mStrdup と同じ */

char *mStrndup_r(const char *str,int len)
{
	if(!str)
		return NULL;
	else if(len < 0)
		return strdup(str);
	else
		return strndup(str, len);
}


//=============================
// メモリ関連
//=============================


/**@ バッファをゼロクリア
 *
 * @p:buf NULL で何もしない */

void mMemset0(void *buf,mlksize size)
{
	if(buf)
		memset(buf, 0, size);
}

/**@ メモリバッファ複製
 *
 * @d:新しくメモリを確保し、データをコピーする。
 * 
 * @p:src NULL の場合、NULL を返す
 * @r:複製されたバッファのポインタ。NULL で失敗。 */

void *mMemdup(const void *src,mlksize size)
{
	void *buf;

	if(!src) return NULL;

	buf = mMalloc(size);
	if(buf)
		memcpy(buf, src, size);

	return buf;
}


//===========================
// 文字列関連
//===========================


/**@ 文字列の長さ取得
 *
 * @p:str NULL の場合、0 が返る */

int mStrlen(const char *str)
{
	if(str)
		return strlen(str);
	else
		return 0;
}

/**@ 文字列複製 (長さ取得)
 *
 * @d:dst に複製した文字列のポインタを格納し、戻り値で複製した文字の長さを返す。
 *
 * @p:str NULL の場合、*dst には NULL が入り、戻り値は 0 となる。
 * @r:文字列の長さ */

int mStrdup_getlen(const char *str,char **dst)
{
	if(str)
	{
		*dst = mStrdup(str);
		return strlen(str);
	}
	else
	{
		*dst = NULL;
		return 0;
	}
}

/**@ 文字列複製 (解放)
 *
 * @d:*dst のポインタを解放した後、src の文字列を複製して *dst にセットする。
 *
 * @p:dst *dst が NULL なら解放はしない
 * @r:*dst と同じ値が返る */

char *mStrdup_free(char **dst,const char *src)
{
	mFree(*dst);

	return (*dst = mStrdup(src));
}

/**@ 文字列複製 (大文字変換)
 *
 * @d:アルファベットを大文字に変換して複製する */

char *mStrdup_upper(const char *str)
{
	char *buf,*p,c;

	buf = mStrdup(str);

	if(buf)
	{
		for(p = buf; (c = *p); p++)
		{
			if(c >= 'a' && c <= 'z')
				*p = c - 0x20;
		}
	}

	return buf;
}

/**@ 文字列を指定サイズに収めてコピー
 *
 * @d:コピーした文字列は、必ず NULL で終わる。
 *
 * @p:dst コピー先
 * @p:src コピー元
 * @p:size コピー先の最大バイト数 (NULL 文字含む)
 * @r:コピーした文字数 (NULL 文字は含まない) */

int mStrncpy(char *dst,const char *src,int size)
{
	int len = strlen(src);

	if(size <= 0)
		return 0;
	else if(len < size)
		//NULL 文字含めすべてコピー
		memcpy(dst, src, len + 1);
	else
	{
		len = size - 1;

		memcpy(dst, src, len);
		dst[len] = 0;
	}

	return len;
}


//========================
// 色関連
//========================


/**@ RGB のアルファ合成 (アルファ値最大 256)
 *
 * @d:dst の上に src をアルファ値 a で合成した色を取得
 *
 * @p:a アルファ値 (0-256) */

mRgbCol mBlendRGB_a256(mRgbCol src,mRgbCol dst,int a)
{
	int sr,sg,sb,dr,dg,db;

	sr = MLK_RGB_R(src);
	sg = MLK_RGB_G(src);
	sb = MLK_RGB_B(src);
	
	dr = MLK_RGB_R(dst);
	dg = MLK_RGB_G(dst);
	db = MLK_RGB_B(dst);

	sr = ((sr - dr) * a >> 8) + dr;
	sg = ((sg - dg) * a >> 8) + dg;
	sb = ((sb - db) * a >> 8) + db;

	return (sr << 16) | (sg << 8) | sb;
}
