/* 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); }