/* vim: ts=4 sw=4 sts=4 ff=unix fenc=utf-8 :
* =====================================================================
* sc_assert.c
* Copyright (c) 2003 - 2011 sys0tem
* LICENSE :
* LGPL (GNU Lesser General Public License - Version 3,29 June 2007)
* http://www.gnu.org/copyleft/lesser.html
* or
* EPL (Eclipse Public License - v1.0)
* http://www.eclipse.org/legal/epl-v10.html
* =====================================================================
*/
#include <stdlib.h>
#include <string.h>
#include <sc_assert.h>
/* --------------------------------------------------------------------
* 定数定義
* --------------------------------------------------------------------
*/
/* assert エラー時に呼び出す最大関数登録数 */
#define SC_ASSERT_ATEXIT_FUNC_MAX (32)
/* --------------------------------------------------------------------
* 内部変数
* --------------------------------------------------------------------
*/
static FILE* SC_assertOutput = NULL;
static void (*SC_assertAtExitFuncs[SC_ASSERT_ATEXIT_FUNC_MAX])(void);
static int SC_assertAtExitFuncSize = 0;
/* --------------------------------------------------------------------
* 内部関数 プロトタイプ宣言
* --------------------------------------------------------------------
*/
static void SC_assertAtExitRun(void);
/**
* エラー出力先を設定します。
* 未初期化かつ fp が NULL の場合、stderr を設定します。
*
* @param fp エラー出力先
*/
void SC_setAssertOutput(FILE* fp)
{
if (fp == NULL)
{
if (SC_assertOutput == NULL)
{
SC_assertOutput = stderr;
}
}
else
{
SC_assertOutput = fp;
}
}
/**
* エラー出力先をクリアします。
*/
void SC_clearAssertOutput(void)
{
SC_assertOutput = NULL;
}
/**
* assert にてエラーが発生した際に実行する関数を登録します。
*
* @param func 登録する関数
* @return true/false (登録成功/登録失敗)
*/
bool SC_assertAtExit(void (*func)(void))
{
if (SC_assertAtExitFuncSize < SC_ASSERT_ATEXIT_FUNC_MAX)
{
SC_assertAtExitFuncs[SC_assertAtExitFuncSize] = func;
SC_assertAtExitFuncSize++;
return true;
}
return false;
}
/**
* assert にてエラーが発生した際に実行する関数をクリアします。
*/
void SC_assertAtExitClear(void)
{
SC_assertAtExitFuncSize = 0;
}
/**
* 指定された val が偽の場合、プログラムの実行を停止します。
*
* @param val 値
* @param valName 変数名
* @param file 対象ソースファイル
* @param line 行番号
* @param func 関数名
*/
void SC_assert_(long val, const char* valName,
const char* file, int line, const char* func)
{
if (!val)
{
/* 出力先初期化 */
SC_setAssertOutput(NULL);
fprintf(SC_assertOutput,
SC_ASSERT_HEAD_FORMAT "%s is not true (val = %ld)\n",
file, line, func, valName, val);
SC_assertAtExitRun();
}
}
/**
* 指定された val2 が val1 と異なる値の場合、
* プログラムの実行を停止します。
*
* @param val1 比較する値1
* @param val2 比較する値2
* @param valName 変数名
* @param file 対象ソースファイル
* @param line 行番号
* @param func 関数名
*/
void SC_assertNumber_(long val1, long val2,
const char* valName,
const char* file, int line, const char* func)
{
if (val1 != val2)
{
SC_setAssertOutput(NULL);
fprintf(SC_assertOutput,
SC_ASSERT_HEAD_FORMAT "%s is not %ld (val2 = %ld)\n",
file, line, func, valName, val1, val2);
SC_assertAtExitRun();
}
}
/**
* 指定された val2 が val1 と異なる文字列の場合、
* プログラムの実行を停止します。
*
* @param val1 比較する文字列1
* @param val2 比較する文字列2
* @param valName 変数名
* @param file 対象ソースファイル
* @param line 行番号
* @param func 関数名
*/
void SC_assertString_(const char* val1, const char* val2,
const char* valName,
const char* file, int line, const char* func)
{
if (val1 == NULL)
{
if (val2 == NULL)
{ /* どちらも NULL */
return;
}
/* val2 != NULL */
SC_setAssertOutput(NULL);
fprintf(SC_assertOutput,
SC_ASSERT_HEAD_FORMAT "%s is not NULL (val2 = %s)\n",
file, line, func, valName, val2);
SC_assertAtExitRun();
}
else if (val2 == NULL)
{ /* val1 != NULL */
SC_setAssertOutput(NULL);
fprintf(SC_assertOutput,
SC_ASSERT_HEAD_FORMAT "%s is NULL (val1 = %s)\n",
file, line, func, valName, val1);
SC_assertAtExitRun();
}
if (strcmp(val1, val2) != 0)
{ /* 不一致 */
SC_setAssertOutput(NULL);
fprintf(SC_assertOutput,
SC_ASSERT_HEAD_FORMAT "%s is not %s (val2 = %s)\n",
file, line, func, valName, val1, val2);
SC_assertAtExitRun();
}
}
/**
* 指定された val2 が val1 と異なる文字列の場合、
* プログラムの実行を停止します。
*
* @param val1 比較する文字列1
* @param val2 比較する文字列2
* @param valName 変数名
* @param file 対象ソースファイル
* @param line 行番号
* @param func 関数名
*/
void SC_assertMemory_(const void* val1, const void* val2,
size_t size,
const char* valName,
const char* file, int line, const char* func)
{
if (val1 == NULL)
{
if (val2 == NULL)
{ /* どちらも NULL */
return;
}
/* val1 != NULL */
SC_setAssertOutput(NULL);
fprintf(SC_assertOutput,
SC_ASSERT_HEAD_FORMAT "%s is not NULL\n",
file, line, func, valName);
SC_assertAtExitRun();
}
else if (val2 == NULL)
{ /* val2 != NULL */
SC_setAssertOutput(NULL);
fprintf(SC_assertOutput,
SC_ASSERT_HEAD_FORMAT "%s is NULL\n",
file, line, func, valName);
SC_assertAtExitRun();
}
if (memcmp(val1, val2, size) != 0)
{ /* 不一致 */
SC_setAssertOutput(NULL);
fprintf(SC_assertOutput,
SC_ASSERT_HEAD_FORMAT "%s is not an expected value\n",
file, line, func, valName);
SC_assertAtExitRun();
}
}
/* --------------------------------------------------------------------
* ASSERT OFF の際のダミー関数
* --------------------------------------------------------------------
*/
long SC_assert_dummyValue;
const void* SC_assert_dummyPtr;
void SC_assertDummy_(long val)
{
SC_assert_dummyValue = val;
}
void SC_assertNumberDummy_(long val1, long val2)
{
SC_assert_dummyValue = (val1 & val2);
}
void SC_assertStringDummy_(const char* val1, const char* val2)
{
SC_assert_dummyPtr = val1;
SC_assert_dummyPtr = val2;
}
void SC_assertMemoryDummy_(
const void* val1, const void* val2, size_t size)
{
SC_assert_dummyPtr = val1;
SC_assert_dummyPtr = val2;
SC_assert_dummyValue = (long) size;
}
/* --------------------------------------------------------------------
* 内部関数
* --------------------------------------------------------------------
*/
/**
* 登録されている関数を順次実行します。
*/
static
void SC_assertAtExitRun(void)
{
int index;
for (index = (SC_assertAtExitFuncSize - 1); index >= 0; index--)
{
SC_assertAtExitFuncs[index]();
}
exit(1);
}