Newer
Older
snipet / kyscript / trunk / lib / nstdc / src / nstdc_assert.c
  1. /**
  2. * @file nstdc_assert.c
  3. * @brief アサーションを扱うモジュール
  4. * @author Nomura Kei
  5. * @copyright 2003 - 2017 Nomura Kei
  6. * License: New BSD License (3-cclause BSD license)
  7. */
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <string.h>
  11.  
  12. #include <nstdc_assert.h>
  13.  
  14. /** デフォルトハンドラの出力先 */
  15. #define DEFAULT_OUTPUT stderr
  16.  
  17.  
  18. /* -----------------------------------------------------------------------------
  19. * 内部関数 プロトタイプ宣言
  20. * -----------------------------------------------------------------------------
  21. */
  22. static void default_handler (long val,
  23. const char* vname, const char* file, int line, const char* func);
  24.  
  25. static void default_handler_num(long v1, long v2,
  26. const char* vname, const char* file, int line, const char* func);
  27.  
  28. static void default_handler_str(const char* v1, const char* v2 ,
  29. const char* vname, const char* file, int line, const char* func);
  30.  
  31. static void default_handler_mem(const void* v1, const void* v2, size_t size,
  32. const char* vname, const char* file, int line, const char* func);
  33.  
  34. static void default_handler_bef(bool is_error);
  35. static void default_handler_aft(bool is_error);
  36. static void assert_init(void);
  37.  
  38.  
  39.  
  40. /* -----------------------------------------------------------------------------
  41. * 内部変数
  42. * -----------------------------------------------------------------------------
  43. */
  44. /** アサーションエラー発生時に呼び出されるハンドラ関数. */
  45. static NstdcAssertHandlers assert_handlers;
  46.  
  47.  
  48. /**
  49. * アサーション発生時に呼び出されるハンドラ関数を設定します.
  50. * 指定がないハンドラは, デフォルトのハンドラが使用されます.
  51. *
  52. * @param handlers アサーション発生時に呼び出されるハンドラ
  53. */
  54. void nstdc_assert_set_handlers(NstdcAssertHandlers* handlers)
  55. {
  56. if (handlers->handler != NULL) { assert_handlers.handler = handlers->handler; }
  57. if (handlers->handler_num != NULL) { assert_handlers.handler_num = handlers->handler_num; }
  58. if (handlers->handler_str != NULL) { assert_handlers.handler_str = handlers->handler_str; }
  59. if (handlers->handler_mem != NULL) { assert_handlers.handler_mem = handlers->handler_mem; }
  60. if (handlers->handler_bef != NULL) { assert_handlers.handler_bef = handlers->handler_bef; }
  61. if (handlers->handler_aft != NULL) { assert_handlers.handler_aft = handlers->handler_aft; }
  62. }
  63.  
  64.  
  65. /**
  66. * 指定された val が偽の場合, 予め登録されているハンドラ関数 (handler) を呼び出します.
  67. * ※handler_bef, handler_aft は常に呼び出されます.
  68. *
  69. * @param val 値
  70. * @param vname 変数名
  71. * @param file ソースファイル名
  72. * @param line 行番号
  73. * @param func 関数名
  74. */
  75. void nstdc_assert_(long val, const char* vname,
  76. const char* file, int line, const char* func)
  77. {
  78. bool is_error = !val;
  79. assert_init();
  80. assert_handlers.handler_bef(is_error);
  81. if (is_error)
  82. {
  83. assert_handlers.handler(val, vname, file, line, func);
  84. }
  85. assert_handlers.handler_aft(is_error);
  86. }
  87.  
  88.  
  89. /**
  90. * 指定された v1, v2 が異なる場合, 予め登録されているハンドラ関数 (handler_num) を呼び出します.
  91. * ※handler_bef, handler_aft は常に呼び出されます.
  92. *
  93. * @param v1 比較する値1
  94. * @param v2 比較する値2
  95. * @param vname 変数名
  96. * @param file ソースファイル名
  97. * @param line 行番号
  98. * @param func 関数名
  99. */
  100. void nstdc_assert_num_(long v1 , long v2,
  101. const char* vname, const char* file, int line, const char* func)
  102. {
  103. bool is_error = (v1 != v2);
  104. assert_init();
  105. assert_handlers.handler_bef(is_error);
  106. if (is_error)
  107. {
  108. assert_handlers.handler_num(v1, v2, vname, file, line, func);
  109. }
  110. assert_handlers.handler_aft(is_error);
  111. }
  112.  
  113.  
  114. /**
  115. * 指定された v1, v2 が異なる場合, 予め登録されているハンドラ関数 (handler_str) を呼び出します.
  116. * ※handler_bef, handler_aft は常に呼び出されます.
  117. *
  118. * @param v1 比較する文字列1
  119. * @param v2 比較する文字列2
  120. * @param vname 変数名
  121. * @param file ソースファイル名
  122. * @param line 行番号
  123. * @param func 関数名
  124. */
  125. void nstdc_assert_str_(const char* v1 , const char* v2,
  126. const char* vname, const char* file, int line, const char* func)
  127. {
  128. int ret;
  129. bool is_error;
  130. assert_init();
  131. if ((v1 != NULL) && (v2 != NULL))
  132. { /* v1, v2 どちらも NULL でなければ文字列比較 */
  133. ret = strcmp(v1, v2);
  134. is_error = (ret != 0);
  135. }
  136. else if ((v1 == NULL) && (v2 == NULL))
  137. { /* v1, v2 どちらも NULL であれば一致とする */
  138. is_error = false;
  139. }
  140. else
  141. { /* v1, v2 どちらかが NULL のため不一致 */
  142. is_error = true;
  143. }
  144.  
  145. /* ハンドラ関数を呼び出す */
  146. assert_handlers.handler_bef(is_error);
  147. if (is_error)
  148. {
  149. assert_handlers.handler_str(v1, v2, vname, file, line, func);
  150. }
  151. assert_handlers.handler_aft(is_error);
  152. }
  153.  
  154.  
  155. /**
  156. * 指定された v1, v2 が異なる場合, 予め登録されているハンドラ関数 (handler_mem) を呼び出します.
  157. * ※handler_bef, handler_aft は常に呼び出されます.
  158. *
  159. * @param v1 比較するデータ1
  160. * @param v2 比較するデータ2
  161. * @param size 比較するデータサイズ
  162. * @param vname 変数名
  163. * @param file ソースファイル名
  164. * @param line 行番号
  165. * @param func 関数名
  166. */
  167.  
  168. void nstdc_assert_mem_(const char* v1, const char* v2, size_t size,
  169. const char* vname, const char* file, int line, const char* func)
  170. {
  171. int ret;
  172. bool is_error;
  173. assert_init();
  174. if ((v1 != NULL) && (v2 != NULL))
  175. { /* v1, v2 どちらも NULL でなければデータ比較 */
  176. ret = memcmp(v1, v2, size);
  177. is_error = (ret != 0);
  178. }
  179. else if ((v1 == NULL) && (v2 == NULL))
  180. { /* v1, v2 どちらも NULL であれば一致とする */
  181. is_error = false;
  182. }
  183. else
  184. { /* v1, v2 どちらかが NULL のため不一致 */
  185. is_error = true;
  186. }
  187.  
  188. /* ハンドラ関数を呼び出す */
  189. assert_handlers.handler_bef(is_error);
  190. if (is_error)
  191. {
  192. assert_handlers.handler_mem(v1, v2, size, vname, file, line, func);
  193. }
  194. assert_handlers.handler_aft(is_error);
  195. }
  196.  
  197.  
  198. /* -----------------------------------------------------------------------------
  199. * 以下, 内部関数実装
  200. * -----------------------------------------------------------------------------
  201. */
  202.  
  203. /**
  204. * デフォルトのハンドラ関数(真偽).
  205. *
  206. * @param val 値
  207. * @param vname 変数名
  208. * @param file ソースファイル名
  209. * @param line 行番号
  210. * @param func 関数名
  211. */
  212. static
  213. void default_handler(long val,
  214. const char* vname, const char* file, int line, const char* func)
  215. {
  216. fprintf(DEFAULT_OUTPUT, "%s:%d:%s %s is not true (val = %ld)\n", file, line, func, vname, val);
  217. }
  218.  
  219.  
  220. /**
  221. * デフォルトのハンドラ関数(数値比較).
  222. *
  223. * @param v1 比較する値1
  224. * @param v2 比較する値2
  225. * @param vname 変数名
  226. * @param file ソースファイル名
  227. * @param line 行番号
  228. * @param func 関数名
  229. */
  230. static
  231. void default_handler_num(long v1, long v2,
  232. const char* vname, const char* file, int line, const char* func)
  233. {
  234. fprintf(DEFAULT_OUTPUT, "%s:%d:%s %s is not %ld (v2 = %ld)\n", file, line, func, vname, v1, v2);
  235. }
  236.  
  237.  
  238. /**
  239. * デフォルトのハンドラ関数(文字列比較).
  240. *
  241. * @param v1 比較する文字列1
  242. * @param v2 比較する文字列2
  243. * @param vname 変数名
  244. * @param file ソースファイル名
  245. * @param line 行番号
  246. * @param func 関数名
  247. */
  248. static
  249. void default_handler_str(const char* v1, const char* v2,
  250. const char* vname, const char* file, int line, const char* func)
  251. {
  252. const char* v1str = (v1 == NULL) ? "(NULL)" : v1;
  253. const char* v2str = (v2 == NULL) ? "(NULL)" : v2;
  254. fprintf(DEFAULT_OUTPUT, "%s:%d:%s %s is not %s (v2 = %s)\n", file, line, func, vname, v1str, v2str);
  255. }
  256.  
  257.  
  258. /**
  259. * デフォルトのハンドラ関数(メモリ比較).
  260. *
  261. * @param v1 比較するデータ1
  262. * @param v2 比較するデータ2
  263. * @param vname 変数名
  264. * @param file ソースファイル名
  265. * @param line 行番号
  266. * @param func 関数名
  267. */
  268. static
  269. void default_handler_mem(const void* v1, const void* v2, size_t size,
  270. const char* vname, const char* file, int line, const char* func)
  271. {
  272. UNUSED_VARIABLE(size);
  273. if (v1 == NULL)
  274. { /* v1 が NULL で v2 が NULL でない */
  275. fprintf(DEFAULT_OUTPUT, "%s:%d:%s %s is not NULL\n", file, line, func, vname);
  276. }
  277. else if (v2 == NULL)
  278. { /* v2 が NULL で v1 が NULL でない */
  279. fprintf(DEFAULT_OUTPUT, "%s:%d:%s %s is NULL\n", file, line, func, vname);
  280. }
  281. else
  282. { /* v1, v2 共に NULL でなく不一致 */
  283. fprintf(DEFAULT_OUTPUT, "%s:%d:%s %s is not an expected value\n", file, line, func, vname);
  284. }
  285. }
  286.  
  287.  
  288. /**
  289. * アサーションの前処理として呼び出されるデフォルトハンドラ関数.
  290. * 本関数ではなにもしません.
  291. *
  292. * @param is_error true/false (アサーションエラー発生/エラーなし)
  293. */
  294. static
  295. void default_handler_bef(bool is_error)
  296. {
  297. /* Nothing to do. */
  298. UNUSED_VARIABLE(is_error);
  299. }
  300.  
  301.  
  302. /**
  303. * アサーションの後処理として呼び出されるハンドラ関数.
  304. * アサーションエラー発生時に, abort する.
  305. *
  306. * @param is_error true/false (アサーションエラー発生/エラーなし)
  307. */
  308. static
  309. void default_handler_aft(bool is_error)
  310. {
  311. if (is_error)
  312. { /* アサーションエラー発生時は abort */
  313. abort();
  314. }
  315. }
  316.  
  317.  
  318.  
  319.  
  320. /**
  321. * アサーションの初期化を実施します.
  322. * 初期化では, アサーションエラー発生時のデフォルトハンドラを設定します.
  323. * 初期化は一度だけ実施されます.
  324. */
  325. static
  326. void assert_init(void)
  327. {
  328. static bool isinit = false;
  329. if (!isinit)
  330. {
  331. assert_handlers.handler = default_handler;
  332. assert_handlers.handler_num = default_handler_num;
  333. assert_handlers.handler_str = default_handler_str;
  334. assert_handlers.handler_mem = default_handler_mem;
  335. assert_handlers.handler_bef = default_handler_bef;
  336. assert_handlers.handler_aft = default_handler_aft;
  337. isinit = true;
  338. }
  339. }
  340.