/**
 * @file      nstdc_errno.c
 * @brief     エラー番号を扱うモジュール
 * @author    Nomura Kei
 * @copyright 2003 - 2017  Nomura Kei
 * License: New BSD License (3-cclause BSD license)
 *
 * 直近に発生したエラー番号を扱います.
 */
#include <nstdc_errno.h>

#include <nstdc_os.h>

#if (!nstdc_is_windows())
#include <string.h>
#include <errno.h>
#endif


/**
 * 当該スレッドで直近に発生したエラー番号を取得します.
 *
 * @return エラー番号
 */
int nstdc_get_errno(void)
{
#if (nstdc_is_windows())
	return GetLastError();
#else
	return errno;
#endif
}


/**
 * エラー番号を設定します.
 *
 * @param errnum 設定するエラー番号
 */
void nstdc_set_errno(int errnum)
{
#if (nstdc_is_windows())
	SetLastError(errnum);
#else
	errno = errnum;
#endif
}



/**
 * 指定された errnum に対応するエラーメッセージを buf に格納します.
 * メッセージの獲得に成功した場合 true を返します.
 *
 * @param errnum エラー番号
 * @param buf    エラーメッセージを格納するバッファ
 * @param buflen バッファのサイズ
 */
bool nstdc_get_errmsg(int errnum, char* buf, size_t buflen)
{
	bool result;
#if (nstdc_is_windows())
	int ret = FormatMessage(
			FORMAT_MESSAGE_FROM_SYSTEM						/* 動作フラグ			*/
			| FORMAT_MESSAGE_IGNORE_INSERTS,
			0,												/* メッセージ定義位置	*/
			errnum,											/* エラーコード			*/
			MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),		/* 言語ID				*/
			buf,											/* バッファアドレス		*/
			buflen,											/* バッファサイズ		*/
			0);												/* 挿入句				*/
	result = (ret != 0);

#elif ((_POSIX_C_SOURCE >= 200112L || __XOPEN_SOURCE >= 600) && ! _GNU_SOURCE)
	/* XSI準拠 stderror_r が提供されている */
	int ret = strerror_r(errnum, buf, buflen);
	result = (ret == 0);

#else
	/* 上記以外の場合, ANSI準拠 strerror(errnum) を使用する	*/
	char*  tmpmsg = strerror(errnum);
	size_t size   = strlen(tmpmsg) + 1;
	if (size > buflen)
	{	/* バッファサイズが足りない	*/
		nstdc_set_errno(ERANGE);
		result = false;
	}
	else
	{
		strncpy(buf, tmpmsg, size);
		result = true;
	}

#endif

	return result;

}

