- /**
- * @file nstdc_assert.c
- * @brief アサーションを扱うモジュール
- * @author Nomura Kei
- * @copyright 2003 - 2017 Nomura Kei
- * License: New BSD License (3-cclause BSD license)
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
-
- #include <nstdc_assert.h>
-
- /** デフォルトハンドラの出力先 */
- #define DEFAULT_OUTPUT stderr
-
-
- /* -----------------------------------------------------------------------------
- * 内部関数 プロトタイプ宣言
- * -----------------------------------------------------------------------------
- */
- static void default_handler (long val,
- const char* vname, const char* file, int line, const char* func);
-
- static void default_handler_num(long v1, long v2,
- const char* vname, const char* file, int line, const char* func);
-
- static void default_handler_str(const char* v1, const char* v2 ,
- const char* vname, const char* file, int line, const char* func);
-
- static void default_handler_mem(const void* v1, const void* v2, size_t size,
- const char* vname, const char* file, int line, const char* func);
-
- static void default_handler_bef(bool is_error);
- static void default_handler_aft(bool is_error);
- static void assert_init(void);
-
-
-
- /* -----------------------------------------------------------------------------
- * 内部変数
- * -----------------------------------------------------------------------------
- */
- /** アサーションエラー発生時に呼び出されるハンドラ関数. */
- static NstdcAssertHandlers assert_handlers;
-
-
- /**
- * アサーション発生時に呼び出されるハンドラ関数を設定します.
- * 指定がないハンドラは, デフォルトのハンドラが使用されます.
- *
- * @param handlers アサーション発生時に呼び出されるハンドラ
- */
- void nstdc_assert_set_handlers(NstdcAssertHandlers* handlers)
- {
- if (handlers->handler != NULL) { assert_handlers.handler = handlers->handler; }
- if (handlers->handler_num != NULL) { assert_handlers.handler_num = handlers->handler_num; }
- if (handlers->handler_str != NULL) { assert_handlers.handler_str = handlers->handler_str; }
- if (handlers->handler_mem != NULL) { assert_handlers.handler_mem = handlers->handler_mem; }
- if (handlers->handler_bef != NULL) { assert_handlers.handler_bef = handlers->handler_bef; }
- if (handlers->handler_aft != NULL) { assert_handlers.handler_aft = handlers->handler_aft; }
- }
-
-
- /**
- * 指定された val が偽の場合, 予め登録されているハンドラ関数 (handler) を呼び出します.
- * ※handler_bef, handler_aft は常に呼び出されます.
- *
- * @param val 値
- * @param vname 変数名
- * @param file ソースファイル名
- * @param line 行番号
- * @param func 関数名
- */
- void nstdc_assert_(long val, const char* vname,
- const char* file, int line, const char* func)
- {
- bool is_error = !val;
- assert_init();
- assert_handlers.handler_bef(is_error);
- if (is_error)
- {
- assert_handlers.handler(val, vname, file, line, func);
- }
- assert_handlers.handler_aft(is_error);
- }
-
-
- /**
- * 指定された v1, v2 が異なる場合, 予め登録されているハンドラ関数 (handler_num) を呼び出します.
- * ※handler_bef, handler_aft は常に呼び出されます.
- *
- * @param v1 比較する値1
- * @param v2 比較する値2
- * @param vname 変数名
- * @param file ソースファイル名
- * @param line 行番号
- * @param func 関数名
- */
- void nstdc_assert_num_(long v1 , long v2,
- const char* vname, const char* file, int line, const char* func)
- {
- bool is_error = (v1 != v2);
- assert_init();
- assert_handlers.handler_bef(is_error);
- if (is_error)
- {
- assert_handlers.handler_num(v1, v2, vname, file, line, func);
- }
- assert_handlers.handler_aft(is_error);
- }
-
-
- /**
- * 指定された v1, v2 が異なる場合, 予め登録されているハンドラ関数 (handler_str) を呼び出します.
- * ※handler_bef, handler_aft は常に呼び出されます.
- *
- * @param v1 比較する文字列1
- * @param v2 比較する文字列2
- * @param vname 変数名
- * @param file ソースファイル名
- * @param line 行番号
- * @param func 関数名
- */
- void nstdc_assert_str_(const char* v1 , const char* v2,
- const char* vname, const char* file, int line, const char* func)
- {
- int ret;
- bool is_error;
- assert_init();
- if ((v1 != NULL) && (v2 != NULL))
- { /* v1, v2 どちらも NULL でなければ文字列比較 */
- ret = strcmp(v1, v2);
- is_error = (ret != 0);
- }
- else if ((v1 == NULL) && (v2 == NULL))
- { /* v1, v2 どちらも NULL であれば一致とする */
- is_error = false;
- }
- else
- { /* v1, v2 どちらかが NULL のため不一致 */
- is_error = true;
- }
-
- /* ハンドラ関数を呼び出す */
- assert_handlers.handler_bef(is_error);
- if (is_error)
- {
- assert_handlers.handler_str(v1, v2, vname, file, line, func);
- }
- assert_handlers.handler_aft(is_error);
- }
-
-
- /**
- * 指定された v1, v2 が異なる場合, 予め登録されているハンドラ関数 (handler_mem) を呼び出します.
- * ※handler_bef, handler_aft は常に呼び出されます.
- *
- * @param v1 比較するデータ1
- * @param v2 比較するデータ2
- * @param size 比較するデータサイズ
- * @param vname 変数名
- * @param file ソースファイル名
- * @param line 行番号
- * @param func 関数名
- */
-
- void nstdc_assert_mem_(const char* v1, const char* v2, size_t size,
- const char* vname, const char* file, int line, const char* func)
- {
- int ret;
- bool is_error;
- assert_init();
- if ((v1 != NULL) && (v2 != NULL))
- { /* v1, v2 どちらも NULL でなければデータ比較 */
- ret = memcmp(v1, v2, size);
- is_error = (ret != 0);
- }
- else if ((v1 == NULL) && (v2 == NULL))
- { /* v1, v2 どちらも NULL であれば一致とする */
- is_error = false;
- }
- else
- { /* v1, v2 どちらかが NULL のため不一致 */
- is_error = true;
- }
-
- /* ハンドラ関数を呼び出す */
- assert_handlers.handler_bef(is_error);
- if (is_error)
- {
- assert_handlers.handler_mem(v1, v2, size, vname, file, line, func);
- }
- assert_handlers.handler_aft(is_error);
- }
-
-
- /* -----------------------------------------------------------------------------
- * 以下, 内部関数実装
- * -----------------------------------------------------------------------------
- */
-
- /**
- * デフォルトのハンドラ関数(真偽).
- *
- * @param val 値
- * @param vname 変数名
- * @param file ソースファイル名
- * @param line 行番号
- * @param func 関数名
- */
- static
- void default_handler(long val,
- const char* vname, const char* file, int line, const char* func)
- {
- fprintf(DEFAULT_OUTPUT, "%s:%d:%s %s is not true (val = %ld)\n", file, line, func, vname, val);
- }
-
-
- /**
- * デフォルトのハンドラ関数(数値比較).
- *
- * @param v1 比較する値1
- * @param v2 比較する値2
- * @param vname 変数名
- * @param file ソースファイル名
- * @param line 行番号
- * @param func 関数名
- */
- static
- void default_handler_num(long v1, long v2,
- const char* vname, const char* file, int line, const char* func)
- {
- fprintf(DEFAULT_OUTPUT, "%s:%d:%s %s is not %ld (v2 = %ld)\n", file, line, func, vname, v1, v2);
- }
-
-
- /**
- * デフォルトのハンドラ関数(文字列比較).
- *
- * @param v1 比較する文字列1
- * @param v2 比較する文字列2
- * @param vname 変数名
- * @param file ソースファイル名
- * @param line 行番号
- * @param func 関数名
- */
- static
- void default_handler_str(const char* v1, const char* v2,
- const char* vname, const char* file, int line, const char* func)
- {
- const char* v1str = (v1 == NULL) ? "(NULL)" : v1;
- const char* v2str = (v2 == NULL) ? "(NULL)" : v2;
- fprintf(DEFAULT_OUTPUT, "%s:%d:%s %s is not %s (v2 = %s)\n", file, line, func, vname, v1str, v2str);
- }
-
-
- /**
- * デフォルトのハンドラ関数(メモリ比較).
- *
- * @param v1 比較するデータ1
- * @param v2 比較するデータ2
- * @param vname 変数名
- * @param file ソースファイル名
- * @param line 行番号
- * @param func 関数名
- */
- static
- void default_handler_mem(const void* v1, const void* v2, size_t size,
- const char* vname, const char* file, int line, const char* func)
- {
- UNUSED_VARIABLE(size);
- if (v1 == NULL)
- { /* v1 が NULL で v2 が NULL でない */
- fprintf(DEFAULT_OUTPUT, "%s:%d:%s %s is not NULL\n", file, line, func, vname);
- }
- else if (v2 == NULL)
- { /* v2 が NULL で v1 が NULL でない */
- fprintf(DEFAULT_OUTPUT, "%s:%d:%s %s is NULL\n", file, line, func, vname);
- }
- else
- { /* v1, v2 共に NULL でなく不一致 */
- fprintf(DEFAULT_OUTPUT, "%s:%d:%s %s is not an expected value\n", file, line, func, vname);
- }
- }
-
-
- /**
- * アサーションの前処理として呼び出されるデフォルトハンドラ関数.
- * 本関数ではなにもしません.
- *
- * @param is_error true/false (アサーションエラー発生/エラーなし)
- */
- static
- void default_handler_bef(bool is_error)
- {
- /* Nothing to do. */
- UNUSED_VARIABLE(is_error);
- }
-
-
- /**
- * アサーションの後処理として呼び出されるハンドラ関数.
- * アサーションエラー発生時に, abort する.
- *
- * @param is_error true/false (アサーションエラー発生/エラーなし)
- */
- static
- void default_handler_aft(bool is_error)
- {
- if (is_error)
- { /* アサーションエラー発生時は abort */
- abort();
- }
- }
-
-
-
-
- /**
- * アサーションの初期化を実施します.
- * 初期化では, アサーションエラー発生時のデフォルトハンドラを設定します.
- * 初期化は一度だけ実施されます.
- */
- static
- void assert_init(void)
- {
- static bool isinit = false;
- if (!isinit)
- {
- assert_handlers.handler = default_handler;
- assert_handlers.handler_num = default_handler_num;
- assert_handlers.handler_str = default_handler_str;
- assert_handlers.handler_mem = default_handler_mem;
- assert_handlers.handler_bef = default_handler_bef;
- assert_handlers.handler_aft = default_handler_aft;
- isinit = true;
- }
- }
-