errors.c

C:\home\SVGCats_src\src\errors.c

[大目次 | 目次 | 関数 | マクロ]

大目次

目次

関数一覧

マクロ一覧


   1|/***************************************************************************
   2|  1. <<< テスト&デバッグツール (errors) >>> 
   3|
   4|(テストツール)
   5|・常時テストするように、チェックコードをプログラムに埋め込んでおきます。
   6|  (ASSERT コマンド、ERROR コマンド)
   7|
   8|(デバッグツール)
   9|・デバッグの際、変数の値を確認するために、汎用の printf があります。
  10|  (Errors_printf コマンド)
  11|・Errors_printf で確認できないものの状態を確認するために、プログラムを
  12|  停止するコマンドがあります。(Errors_break コマンド)
  13|・エラーが起きるケースを特定するために、カウンタがあります。
  14|  (Errors_counter コマンド)
  15|・Visual Studio 環境では、Errors_exit の中の exit 関数にブレークポイントを
  16|  貼ると、関数のコールスタックを確認することが出来ます。
  17|  [EXIT_POINT] のキーワードで検索できます。(ASSERT するところと、
  18|  exit するところの2箇所)
  19|・SDV 環境では、_bf にブレークポイントを設定します。
  20|  もし、設定し忘れて、プログラムが止まったと思ったら ESC を押してく
  21|  ださい。
  22|****************************************************************************/
  23|
  24|#include "mixer_precomp.h"  /* Auto precompiled header, Look at mixer-... folder */
  25|// #pragma hdrstop ("mixer_precomp")
  26|
  27|#if  defined(_MSC_VER) && ! defined(UNDER_CE)
  28|  #include <conio.h>
  29|#endif
  30|#if  ( defined(_WIN32) && !defined(FOR_DOS32) ) && !defined(__BORLANDC__)
  31|  //#include "windows.h"
  32|#endif
  33|
  34|#define  STDLIBS_INCLUDE
  35|#define  STDLIBS_INCLUDE_STDIO_H
  36|#define  STDLIBS_INCLUDE_STDLIB_H
  37|#define  STDLIBS_INCLUDE_STRING_H
  38|#define  STDLIBS_INCLUDE_STDARG_H
  39|
  40|#if defined(USES_MXP_AUTOINC)
  41| #include "errors.ah"  /* Auto include header, Look at mixer-... folder */
  42|#endif
  43|
  44|#if  defined(USES_FILEX) && !defined(FOR_WINCE)
  45| #include  <errno.h>
  46|#endif
  47|
  48|#if  defined(__BORLANDC__) && defined(FOR_DOS32)
  49|  #include <conio.h>
  50|#endif
  51|
  52|
  53|
  54|#ifdef  vsprintf
  55|#undef  vsprintf
  56|int  vsprintf( char*, const char*, ... );
  57|#endif
  58|
  59|char*  Errors_printf_imp2( const char* fmt, va_list va );
  60|
  61|ERRORS_VERSION( errors, 2 );
  62|
  63|#ifdef  FOR_32BIT
  64|  #define  Errors_ErrValue  0xEEEEEEEE
  65|#else
  66|  #define  Errors_ErrValue  0xEEEE
  67|#endif
  68| 
  69|/*-------------------------------------------------------------------------*/
  70|/* 2. <<<< ◆エラー処理ツール >>>>  */ 
  71|/*-------------------------------------------------------------------------*/
  72|
  73|int  Errors_bStrongExit = false;
  74|int  Errors_errDupCount = 0;   /* エラー処理中のエラーの重複数 */
  75| 
  76|/***************************************************************************
  77|  2-1. <<< [Errors_error_imp] エラーを発生する >>> 
  78|【補足】
  79|・内部用です。error マクロから呼出されます。
  80|【内部補足】
  81|・Except2 が無い場合のみ、ASSERT, ASSERT2_0, error, error2_0 から呼び出されます。
  82|・COUNT マクロを使用したとき、プロセッサの通過回数が表示されます。
  83|  ただし、COUNT マクロにプロセッサが一度も通過していないときは表示されません。
  84|****************************************************************************/
  85|#ifndef  USES_EXCEPT2
  86|void  Errors_error_imp( const char* file, int line, int code, char* codeStr,
  87|  char* fmt, ... )
  88|{
  89|  static int err_id = 0;
  90|  va_list  va;
  91|  #ifdef  NDEBUG
  92|    int    ret = ERRORS_IGNORE;
  93|  #else
  94|    int    ret = ERRORS_EXIT;
  95|  #endif
  96|  int   msg2_headSize;
  97|  char  msg[1024];
  98|  char  msg2[1024];
  99|
 100|  #if  defined(ERRORS_PRINTF_TO_WINDOW) && defined(FOR_WIN32)
 101|    Errors_startPool_release();
 102|  #endif
 103|
 104|  /* エラーID の作成 */
 105|  err_id ++;
 106|
 107|  /* エラーメッセージの作成 */
 108|  va_start( va, fmt );
 109|  vsprintf( msg, fmt, va );
 110|  va_end( va );
 111|
 112|  if ( Errors_count > 0 ) {
 113|    sprintf( msg2, "%s(%d) : id = %d, code = %d, %s, (COUNT=%d) ",
 114|      file, line, err_id, code, codeStr, Errors_count );
 115|  }
 116|  else {
 117|    sprintf( msg2, "%s(%d) : id = %d, code = %d, %s, ",
 118|      file, line, err_id, code, codeStr );
 119|  }
 120|  msg2_headSize = strchr( msg2, '\0' ) - msg2;
 121|  strcpy( msg2 + msg2_headSize, msg );
 122|
 123|  if ( strlen( msg2 ) > sizeof(msg2) ) {
 124|    strcpy( msg2 + sizeof(msg2) - 5, "..." );
 125|    bf( Errors_ErrValue, 0, (int)__FILE__, __LINE__ );
 126|  }
 127|
 128|  #if  defined(USES_ARRX) && defined(USES_OFFSET)
 129|    if ( Errors_MsgPool_isInit( Errors_MsgPool_getGlobl() ) &&
 130|         Errors_Msg_getGlobl()->code != Errors_NoError ) {
 131|      Errors_MsgPool_add( Errors_MsgPool_getGlobl(), Errors_Msg_getGlobl() );
 132|    }
 133|  #endif
 134|  Errors_Msg_init( Errors_Msg_getGlobl(), err_id, code, file, line, "%s", msg2 );
 135|  Errors_Msg_getGlobl()->orgMsg = Errors_Msg_getGlobl()->msg + msg2_headSize;
 136|
 137|
 138|  /* 二重エラーチェック */
 139|  Errors_errDupCount++;
 140|  if ( Errors_errDupCount > 1 ) {
 141|    #if  defined(USES_ARRX) && defined(USES_OFFSET) && defined(USES_MULTASK)
 142|      if ( Errors_InitChk_getOrder( &Errors_MsgPool_getGlobl()->msgs ) < 0 )
 143|        Errors_printf_release( "二重エラーです:%s", msg2 );
 144|      else
 145|        Errors_printf_release( "二重エラーです。catch または finally の中でエラーになっている可能性があります。" );
 146|    #else
 147|      Errors_printf_release( "二重エラーです。catch または finally の中でエラーになっている可能性があります。" );
 148|    #endif
 149|    Errors_printf_release( "%s", msg2 );
 150|    Errors_endAllPool_release();
 151|    Errors_exit( file, line );
 152|  }
 153|
 154|  /* エラーメッセージのヘッダを出力する */
 155|  #if !defined(NDEBUG) && !defined(ERRORS_ERROR_REPORT)
 156|    Errors_printf( "リリース版では、次の詳細情報は表示されません。" );
 157|  #endif
 158|  #if !defined(NDEBUG) || defined(ERRORS_ERROR_REPORT)
 159|    if ( Errors_appName != NULL )
 160|      Errors_printf_release( "Application = %s", Errors_appName );
 161|    if ( Errors_appVersion != NULL )
 162|      Errors_printf_release( "Version = %s", Errors_appVersion );
 163|  #endif
 164|
 165|  /* エラーハンドル関数の呼出し */
 166|  if ( Errors_hdl != NULL ) {
 167|    ret = (*Errors_hdl)( err_id, code, msg2 );
 168|  }
 169|
 170|  /* リリース版ではエラーを無視する警告 */
 171|  #ifndef  NDEBUG
 172|  if ( Errors_hdl == NULL ) {
 173|    Errors_printf_release( "[warning] リリース版では、次のエラーが無視されます。" );
 174|  }
 175|  #endif
 176|
 177|  /* プログラムの終了 */
 178|  if ( ret == ERRORS_EXIT ) {
 179|    Errors_exit( file, line );
 180|  }
 181|
 182|  /* エラーを無視してプログラムを続行する */
 183|  Errors_clearError();
 184|}
 185|#endif
 186| 
 187|/***************************************************************************
 188|  2-2. <<< [Errors_errorStdlib] 標準ライブラリの errno のエラーを発生させる >>> 
 189|【補足】
 190|・コメントは、Visual Studio 6.0 のヘルプより引用
 191|****************************************************************************/
 192|#if  defined(USES_FILEX) && !defined(FOR_WINCE)
 193|void  Errors_errorStdlib()
 194|{
 195|  char*  s;
 196|
 197|  switch ( errno ) {
 198|
 199|    case ECHILD:
 200|      s = "errno = ECHILD : 子プロセスが存在しない";
 201|      break;
 202|
 203|    case EAGAIN:
 204|      s = "errno = EAGAIN : これ以上プロセスを生成できない。プロセス スロットが足りないか、"
 205|          "メモリ不足か、または最大ネスト レベルに達したために、"
 206|          "新しいプロセスの生成に失敗しました。";
 207|      break;
 208|
 209|    case E2BIG:
 210|      s = "errno = E2BIG : 引数リストが長すぎる";
 211|      break;
 212|
 213|    case EACCES:
 214|      s = "errno = EACCES : アクセスが拒否された。";
 215|      /* ファイルのアクセス権の設定により、指定されたアクセスを行えません。
 216|         このエラーは、ファイルの属性に反した方法でファイル (場合によっては
 217|         ディレクトリ) にアクセスしようとしたときに起こります。
 218|         たとえば、開いていないファイルから読み出そうとしたり、
 219|         既存の読み出し専用ファイルを書き込み用に開こうとしたり、
 220|         ファイルの代わりにディレクトリを開こうとすると、このエラーが起きます。
 221|         MS-DOS オペレーティング システム 3.0 以降では、ロッキングや共有モード違反も
 222|         EACCES によって示されます。
 223|         ファイルまたはディレクトリを既存のディレクトリと同じ名前に変更しようとしたり、
 224|         空でないディレクトリを削除しようとした場合にも、このエラーが発生します。
 225|       */
 226|      break;
 227|
 228|    case EBADF:
 229|      s = "不正なファイル番号。";
 230|      /* 2 つの原因が考えられます。1) 指定されたファイル
 231|         ハンドルが有効なファイル ハンドルの値ではないか、開いているファイルを
 232|         参照していないとき。2) 読み出し専用で開いているファイルまたはデバイスに
 233|         書き込もうとしたとき。
 234|      */
 235|      break;
 236|
 237|    case EDEADLOCK:
 238|      s = "リソースのデッドロックが発生する可能性がある。";
 239|      break;
 240|
 241|    case EDOM:
 242|      s = "数値演算関数の引数が関数のドメイン外の値である。";
 243|      break;
 244|
 245|    case EEXIST:
 246|      s = "ファイルが存在する。既に存在するファイルを作成しようとしています。";
 247|      /* たとえば、_open の呼び出しで _O_CREAT フラグと _O_EXCL フラグを指定したところ、
 248|         指定したファイルが存在している場合です。
 249|      */
 250|      break;
 251|
 252|    case EINVAL:
 253|      s = "不正な引数。たとえば、ファイル ポインタの移動 (fseek の呼び出し) のとき、"
 254|          "指定した元の位置がファイルの先頭より前にある場合です。";
 255|      break;
 256|
 257|    case EMFILE:
 258|      s = "開いているファイルが多すぎる。空いているファイル ハンドルがないので、ファイルを開けません。";
 259|      break;
 260|
 261|    case ENOENT:
 262|      s = "ファイルまたはディレクトリがない。指定されたファイルまたはディレクトリが"
 263|          "存在しないか見つかりません。このメッセージは、指定されたファイルが存在しないか、"
 264|          "パス名の要素が既存のディレクトリを指定していない場合に発生します。";
 265|      break;
 266|
 267|    case ENOEXEC:
 268|      s = "実行ファイルのエラー。実行可能でないか無効な実行可能ファイル形式を"
 269|          "持つファイルを実行しようとしました。";
 270|      break;
 271|
 272|    case ENOMEM:
 273|      s = "メモリ不足。実行しようとした操作に十分なメモリがありません。";
 274|      /* たとえば、子プロセスを実行するためのメモリが不足しているか、または
 275|          _getcwd の呼び出しで割り当て要求が満たされないと、このメッセージが発生します。"; */
 276|      break;
 277|
 278|    case ENOSPC:
 279|      s = "デバイスの空き領域不足。デバイスに書き込み用の領域が残っていません "
 280|          "(たとえば、ディスクがいっぱいになった場合)。";
 281|      break;
 282|
 283|    case ERANGE:
 284|      s = "結果が大きすぎる。数値演算関数の引数が大きすぎて、結果の有効桁数の一部"
 285|          "または全部が失われます。このエラーは、他の関数でも、引数が想定より大きい"
 286|          "(たとえば、_getcwd の buffer 引数が大きすぎる) 場合に発生します。";
 287|      break;
 288|
 289|    case EXDEV:
 290|      s = "デバイス間リンク。rename 関数を使って、別のデバイスにファイルを移動しようとしました。";
 291|      break;
 292|
 293|    ERRORS_SWITCH_DEFAULT_ASSERT;
 294|  }
 295|
 296|  error2_1( Errors_Err_Errno, "%s", s );
 297|}
 298|#endif
 299| 
 300|/***************************************************************************
 301|  2-3. <<< [Errors_clearError] エラーを発生する >>> 
 302|【補足】
 303|・エラーメッセージをエラーが発生していない状態にします。
 304|・エラーが発生したら必ず終了するときや例外を発生させるときは、
 305|  本マクロを使用する必要はありません。エラーメッセージを参照して
 306|  エラーが発生しているか確認するスタイルの場合に、エラー復帰が
 307|  済んだときに使用します。
 308|・プログラムを開始したときも呼び出してください。
 309|****************************************************************************/
 310|void  Errors_clearError()
 311|{
 312|  Errors_Msg_init( Errors_Msg_getGlobl(), 0, Errors_NoError, Errors_ns, 0, Errors_ns );
 313|  Errors_errDupCount = 0;
 314|  #if  defined(ERRORS_PRINTF_TO_WINDOW) && defined(FOR_WIN32)
 315|    Errors_clearPool_release();
 316|  #endif
 317|}
 318|
 319|
 320| 
 321|/***************************************************************************
 322|  2-4. <<< [Errors_warning_imp] Errors_warning の関数部分 >>> 
 323|****************************************************************************/
 324|#if !defined(ERRORS_CUT_DEBUG_TOOL) && !defined(NDEBUG)
 325|int  Errors_nWarning = 0;
 326|
 327|void  Errors_warning_imp( const char* file, int line, const char* fmt, ... )
 328|{
 329|  va_list  va;
 330|  char  msg[4096];
 331|
 332|  va_start( va, fmt );
 333|  sprintf( msg, fmt, va );
 334|  va_end( va );
 335|
 336|  Errors_nWarning ++;
 337|  Errors_printf( "[WARNING] id = %d : %s : %s(%d)",
 338|    Errors_nWarning, msg, file, line );
 339|}
 340|#endif
 341|
 342| 
 343|/***************************************************************************
 344|  2-5. <<< [Errors_exit] エラー停止 >>> 
 345|【補足】
 346|・内部用です。エラーを発生させるには、error マクロを使ってください。
 347|・内部で exit(0xE); を呼び出しています。
 348|・本関数または StdX_exit 関数にブレークポイントを貼れば、プログラムが終了する
 349|  直前の状態でブレークできます。
 350|・C++ のアプリケーションの静的グローバル変数のデストラクタでチェックする場合は、
 351|  ERRORS_NO_EXIT_CHK を #define してください。
 352|【内部補足】
 353|・Errors_error 関数と Except2_Sys_throw_imp 関数から呼出されます。
 354|****************************************************************************/
 355|bool  Errors_bExiting = false;
 356|bool  Errors_bCalledExitHandler = false;
 357|
 358|void  Errors_exit( const char* file, int line )
 359|{
 360|  /* 引数の退避 */
 361|  #ifdef FOR_GHS
 362|    #ifdef FOR_VR
 363|      __asm("move $21, $4");
 364|      __asm("move $22, $5");
 365|    #else
 366|      __asm("mov r6, r21");
 367|      __asm("mov r7, r22");
 368|    #endif
 369|  #endif
 370|  #ifdef FOR_CA732
 371|    __asm("mov r6, r21");
 372|    __asm("mov r7, r22");
 373|  #endif
 374|  #ifdef FOR_GNU
 375|    __asm("mov $6, $21");
 376|    __asm("mov $7, $22");
 377|  #endif
 378|  #ifdef FOR_CODEW
 379|    asm(mov r6, r21);
 380|    asm(mov r7, r22);
 381|  #endif
 382|
 383|  if ( ! Errors_bExiting ) {
 384|    Errors_bExiting = true;
 385|
 386|    #ifndef  ERRORS_NO_EXIT_CHK
 387|      Errors_chkDefault();
 388|    #endif
 389|  }
 390|  if ( Errors_exitHandler != NULL ) {
 391|    if ( Errors_bCalledExitHandler ) {
 392|      Errors_printLowLevel( "ExitHandler 内でエラーが発生しました。" );
 393|      Errors_endAllPool_release();
 394|    }
 395|    else {
 396|      Errors_bCalledExitHandler = true;
 397|      Errors_errDupCount = 0;
 398|      Errors_exitHandler( Errors_paramOfExitHandler );
 399|    }
 400|  }
 401|
 402|  /* プログラム終了 [EXIT_POINT] */
 403|  #ifdef FOR_DOS32
 404|    exit( 0xE );
 405|  #endif
 406|  #ifdef FOR_WIN32
 407|    exit( 0xE );
 408|  #endif
 409|  #ifdef FOR_WINCE
 410|    exit( 0xE );
 411|  #endif
 412|  #ifdef FOR_DOS16
 413|    exit( 0xE );
 414|  #endif
 415|  #ifdef FOR_GHS
 416|    #ifdef FOR_VR
 417|      __asm("move $21, $6");
 418|      __asm("move $22, $7");
 419|      __asm("lui  $4, 0xEEEE");
 420|      __asm("ori  $4, 0xEEEE");
 421|      __asm("lui  $5, 0x0000");
 422|      __asm("ori  $5, 0x0004");
 423|      __asm("jal  exit");
 424|    #else
 425|      __asm("mov r21, r8");
 426|      __asm("mov r22, r9");
 427|      __asm("mov 0xEEEEEEEE, r6");
 428|      __asm("mov 0x00000004, r7");
 429|      __asm("jal  exit");
 430|    #endif
 431|  #endif
 432|  #ifdef FOR_CA732
 433|    __asm("mov r21, r8");
 434|    __asm("mov r22, r9");
 435|    __asm("mov 0xEEEEEEEE, r6");
 436|    __asm("mov 0x00000004, r7");
 437|    __asm("jal exit");
 438|  #endif
 439|  #ifdef FOR_GNU
 440|    __asm("mov $21, $8");
 441|    __asm("mov $22, $9");
 442|    __asm("mov 0xEEEEEEEE, $6");
 443|    __asm("mov 0x00000004, $7");
 444|    __asm("jal exit");
 445|  #endif
 446|  #ifdef FOR_CODEW
 447|    exit(0xE);
 448|  #endif
 449|  file, line;  /* avoid warning */
 450|}
 451|
 452|
 453| 
 454|/***************************************************************************
 455|  2-6. <<< [Errors_chkDefault] プログラム終了時のデフォルトのエラーチェック&表示を行う >>> 
 456|【補足】
 457|・Endeavor(Win2000,VC++6?) でコンパイルした場合、メインウィンドウが閉じる
 458|  前に(OnOK の最後などで)呼び出してください。参考:Errors_endPool
 459|****************************************************************************/
 460|void  Errors_chkDefault()
 461|{
 462|  static  int  count = 0;
 463|  count ++;
 464|
 465|  if ( count == 1 ) {
 466|    bool  bOut = false;
 467|
 468|    #if  defined(ERRORS_PRINTF_TO_WINDOW) && defined(FOR_WIN32)
 469|      Errors_startPool_release();
 470|    #endif
 471|
 472|    if ( Errors_errDupCount > 0 ) {
 473|
 474|      #if defined(USES_ARRX) && defined(USES_OFFSET)
 475|        if ( Errors_InitChk_getOrder( &Errors_MsgPool_getGlobl()->msgs ) >= 0 ) {
 476|          Errors_MsgPool_print( Errors_MsgPool_getGlobl() );
 477|          Errors_Msg_print( Errors_Msg_getGlobl() );
 478|          bOut = true;
 479|        }
 480|      #endif
 481|      if ( ! bOut ) {
 482|        Errors_Msg_print( Errors_Msg_getGlobl() );
 483|        #ifdef  FOR_ENGLISH
 484|          Errors_printf_release( "[warning] Error messages may be overritten, because Errors_MsgPool didn't initialize." );
 485|        #else
 486|          Errors_printf_release( "[warning] Errors_MsgPool を初期化していないので、"
 487|            "上記のエラーメッセージは上書きされたか、"
 488|            "既に対処したエラーである可能性があります。" );
 489|        #endif
 490|      }
 491|    }
 492|
 493|    #ifndef  NDEBUG
 494|      if ( Errors_nWarning > 0 )
 495|        Errors_printf( "[WARNING] warning count = %d", Errors_nWarning );
 496|    #endif
 497|
 498|    /* デフォルトのエラーチェックを行い、ログをファイルに出力する */
 499|    #if  ! defined(ERRORS_CUT_DEBUG_TOOL) && defined(ERRORS_USE_FUNCLOG)
 500|      Errors_FuncLog_print();
 501|    #endif
 502|
 503|    #ifdef  USES_BIGSTACK
 504|      BIGSTACK_CHECK();
 505|    #endif
 506|    ERRORS_FINISHCHK();
 507|
 508|    /* デフォルト・最終チェックが行われたことを表示する */
 509|    #ifndef  NDEBUG
 510|      Errors_printf_release( "Default Final Chk Done." );
 511|    #endif
 512|
 513|    /* 終了直前のエラーメッセージ表示 */
 514|    if ( Errors_errDupCount > 0 ) {
 515|      #ifdef FOR_WIN32
 516|      {
 517|        char*  s = "エラーが発生しました。\r\n"
 518|          "プログラムに原因(バグ)があると考えられるときは、"
 519|          "開発者のホームページでバグ情報を参照するか、"
 520|          "次に表示される詳細情報を eメールで送ってください。";
 521|
 522|        if ( Errors_appName == NULL ) {
 523|          MessageBox( (HWND)Errors_parentWnd, s, "Sage Plaisir Open Source Module",
 524|            MB_OK | MB_ICONERROR );
 525|        }
 526|        else {
 527|          char   msg[1024];
 528|          sprintf( msg, "%s で%s", Errors_appName, s );
 529|          MessageBox( (HWND)Errors_parentWnd, msg, Errors_appName,
 530|            MB_OK | MB_ICONERROR );
 531|        }
 532|        #ifdef  ERRORS_PRINTF_TO_WINDOW
 533|          Errors_endAllPool_release();
 534|        #endif
 535|      }
 536|      #else
 537|        Errors_printf_release( "EXIT" );
 538|      #endif
 539|    }
 540|    else {
 541|      #if  defined(ERRORS_PRINTF_TO_WINDOW) && defined(FOR_WIN32)
 542|        Errors_endAllPool_release();
 543|      #endif
 544|    }
 545|  }
 546|}
 547|
 548| 
 549|/***************************************************************************
 550|  2-7. <<< [Errors_setHandler] エラーハンドラを登録する >>> 
 551|****************************************************************************/
 552|#ifdef  USES_EXCEPT2
 553|void  Errors_setHandler( Errors_Handler hdl )
 554|{
 555|  Except2_Sys_setErrorHandler( hdl );
 556|}
 557|#endif
 558|
 559|
 560| 
 561|/***************************************************************************
 562|  2-8. <<< [Errors_stdErrHandler] 標準的なエラーハンドラ >>> 
 563|【補足】
 564|・Errors_setErrorHandler で登録します。
 565|****************************************************************************/
 566|int  Errors_stdErrHandler( int id, int code, char* msg )
 567|{
 568|  #ifndef  NDEBUG
 569|    if ( code == Errors_ASSERT )
 570|      Errors_break( 0xEEEE );  /* [EXIT_POINT] */
 571|  #endif
 572|
 573|  #ifdef  USES_EXCEPT3
 574|    if ( code != Errors_ASSERT && code != Except3_Err_OutOfTry )
 575|      c_throw( Errors_Msg_getGlobl() );
 576|  #endif
 577|
 578|//  #ifdef  NDEBUG
 579|    /* 下の2行のうちどちらか */
 580|    Errors_printf_release( "%s", msg );
 581|    Errors_MsgPool_print( Errors_MsgPool_getGlobl() );
 582|//  #endif
 583|
 584|  return  ERRORS_EXIT;
 585|}
 586|
 587|
 588| 
 589|/*--------------------------------------------------------------------*/
 590|/* 3. <<<<◆ (Errors_Msg) エラーメッセージ >>>> */ 
 591|/*--------------------------------------------------------------------*/
 592|
 593|
 594|
 595| 
 596|/***************************************************************************
 597|  3-1. <<< [Errors_Msg_init] メッセージを作成する >>> 
 598|****************************************************************************/
 599|void  Errors_Msg_init( Errors_Msg* m, int id, int code, const char* file,
 600|  int line, const char* msg_fmt, ... )
 601|{
 602|  va_list  va;
 603|
 604|  m->id = id;
 605|  m->code = code;
 606|  strcpy( m->file, file );
 607|  m->line = line;
 608|  va_start( va, msg_fmt );
 609|  vsprintf( m->msg, msg_fmt, va );
 610|  va_end( va );
 611|  if ( Errors_count > 0 )
 612|    sprintf( strchr( m->msg, '\0' ), "(COUNT=%d)", Errors_count );
 613|}
 614|
 615| 
 616|/***************************************************************************
 617|  3-2. <<< [Errors_Msg_print] メッセージをデバッグ表示する >>> 
 618|****************************************************************************/
 619|void  Errors_Msg_print( Errors_Msg* m )
 620|{
 621|  #ifdef  NDEBUG
 622|    Errors_printf_release( "%s", m->msg );
 623|  #else
 624|    Errors_printf_release( "[ERROR] %s", m->msg );
 625|  #endif
 626|}
 627|
 628|
 629| 
 630|/***************************************************************************
 631|  3-3. <<< [Errors_Msg_initGlobl] タスク唯一の Errors_Msg 型領域を設定する >>> 
 632|【補足】
 633|・マルチタスク環境でも共有しない Errors_Msg 型のグローバル変数の
 634|  メモリ領域を設定します。初期マルチタスクで呼び出してください。
 635|****************************************************************************/
 636|#ifdef  USES_MULTASK
 637|
 638|Errors_Msg*  Errors_Msg_globl = NULL;
 639|
 640|void  Errors_Msg_initGlobl( Errors_Msg* msgs, int msgs_size )
 641|{
 642|  ASSERT( size >= sizeof( Errors_Msg ) * MulTask_mIdArr );
 643|  Errors_Msg_globl = msgs;
 644|}
 645|
 646|#else
 647|
 648|Errors_Msg  Errors_Msg_globl;
 649|
 650|#endif
 651|
 652| 
 653|/***************************************************************************
 654|  3-4. <<< [Errors_Msg_getGlobl] タスク唯一の Errors_Msg 型グローバル変数を返す >>> 
 655|【補足】
 656|・マルチタスク環境でも共有しない Errors_Msg 型のグローバル変数の
 657|  アドレスを返します。例外を throw するときなどに使用します。
 658|****************************************************************************/
 659|#ifdef  USES_MULTASK
 660|
 661|Errors_Msg*  Errors_Msg_getGlobl()
 662|{
 663|  ASSERT( Errors_Msg_globl != NULL );
 664|  return  &Errors_Msg_globl[MulTask_Sys_getCurIndex()];
 665|}
 666|
 667|#else
 668|
 669|Errors_Msg*  Errors_Msg_getGlobl()
 670|{
 671|  return  &Errors_Msg_globl;
 672|}
 673|
 674|#endif
 675|
 676| 
 677|/*--------------------------------------------------------------------*/
 678|/* 4. <<<<◆ (Errors_MsgPool) エラーメッセージ・プール >>>> */ 
 679|/*--------------------------------------------------------------------*/
 680| 
 681|/***************************************************************************
 682|  4-1. <<< [Errors_MsgPool_initGlobl] タスク唯一の Errors_MsgPool 型領域を設定する >>> 
 683|【補足】
 684|・マルチタスク環境でも共有しない Errors_MsgPool 型のグローバル変数の
 685|  メモリ領域を設定します。初期マルチタスクで呼び出してください。
 686|****************************************************************************/
 687|#ifdef  USES_ARRX
 688|#ifdef  USES_OFFSET
 689|#ifdef  USES_MULTASK
 690|
 691|Errors_MsgPool*  Errors_MsgPool_globl = NULL;
 692|
 693|void  Errors_MsgPool_initGlobl( Errors_MsgPool* sts, int sts_size )
 694|{
 695|  ASSERT( sts_size >= sizeof( Errors_MsgPool ) * MulTask_mIdArr );
 696|  Errors_MsgPool_globl = msgs;
 697|}
 698|
 699|#else
 700|
 701|Errors_MsgPool  Errors_MsgPool_globl;
 702|
 703|#endif
 704|#endif
 705|#endif
 706| 
 707|/***************************************************************************
 708|  4-2. <<< [Errors_MsgPool_isInit] Errors_MsgPool が初期化されているかを返す >>> 
 709|****************************************************************************/
 710|#if  defined(USES_ARRX) && defined(USES_OFFSET)
 711|
 712|bool  Errors_MsgPool_isInit( Errors_MsgPool* m )
 713|{
 714|  return  m->msgs.arr.first != NULL;
 715|}
 716|
 717|#endif
 718| 
 719|/***************************************************************************
 720|  4-3. <<< [Errors_MsgPool_getGlobl] タスク唯一の Errors_MsgPool 型グローバル変数を返す >>> 
 721|【補足】
 722|・マルチタスク環境でも共有しない Errors_MsgPool 型のグローバル変数の
 723|  アドレスを返します。
 724|****************************************************************************/
 725|#ifdef  USES_ARRX
 726|#ifdef  USES_OFFSET
 727|#ifdef  USES_MULTASK
 728|
 729|Errors_MsgPool*  Errors_MsgPool_getGlobl()
 730|{
 731|  ASSERT( Errors_MsgPool_globl != NULL );
 732|  if ( Errors_MsgPool_globl == NULL )
 733|    return  &Errors_MsgPool_globl;
 734|
 735|  return  &Errors_MsgPool_globl[MulTask_Sys_getCurIndex()];
 736|}
 737|
 738|#else
 739|
 740|Errors_MsgPool*  Errors_MsgPool_getGlobl()
 741|{
 742|  return  &Errors_MsgPool_globl;
 743|}
 744|
 745|#endif
 746|#endif
 747|#endif
 748|
 749| 
 750|/***************************************************************************
 751|  4-4. <<< [Errors_MsgPool_print] 登録されているエラーメッセージをすべて表示する >>> 
 752|****************************************************************************/
 753|#ifdef  USES_ARRX
 754|#ifdef  USES_OFFSET
 755|void  Errors_MsgPool_print( Errors_MsgPool* m )
 756|{
 757|  int  i = 1;
 758|  Errors_Msg*  msg;
 759|
 760|  for ( Errors_MsgPool_forEach( m, &msg ) ) {
 761|    #ifdef NDEBUG
 762|      Errors_printf_release( "%s", msg->msg );
 763|    #else
 764|      Errors_printf_release( "[ERROR] %s", msg->msg );
 765|    #endif
 766|    i++;
 767|  }
 768|}
 769|#endif
 770|#endif
 771|
 772| 
 773|/***************************************************************************
 774|  4-5. <<< [Errors_MsgPool_printLowLevel] 登録されているエラーメッセージをすべて表示する >>> 
 775|****************************************************************************/
 776|#ifdef  USES_ARRX
 777|#ifdef  USES_OFFSET
 778|void  Errors_MsgPool_printLowLevel( Errors_MsgPool* m )
 779|{
 780|  int  i = 1;
 781|  Errors_Msg*  msg;
 782|  char  s[4096];
 783|
 784|  for ( Errors_MsgPool_forEach( m, &msg ) ) {
 785|    #ifdef NDEBUG
 786|      sprintf( s, "%s", msg->msg );
 787|    #else
 788|      sprintf( s, "[ERROR] %s", msg->msg );
 789|    #endif
 790|    Errors_printLowLevel( s );
 791|    i++;
 792|  }
 793|}
 794|#endif
 795|#endif
 796|
 797| 
 798|/*--------------------------------------------------------------------*/
 799|/* 5. <<<<◆ テストツール >>>> */ 
 800|/*--------------------------------------------------------------------*/
 801|
 802|char*  Errors_NorSupport_msg = "Not Support in this Version";
 803|char*  Errors_NorSupport_msgFmt = "%s in %s(%d)";
 804|char*  Errors_ChkRet_msg = "return error code = %d";
 805|
 806|/* テストプログラム用 */
 807|char*  Errors_okLabel = "OK.";
 808|char*  Errors_errLabel = "### ERROR EXIST!! ###";
 809|int    Errors_errCount = 0;  /* エラーのカウント */
 810|
 811|#ifndef  USES_EXCEPT2
 812|  Errors_Handler   Errors_hdl = NULL;  /* エラーハンドラのアドレス */
 813|#endif
 814|
 815|Errors_ExitHandler   Errors_exitHandler = NULL;
 816|void*  Errors_paramOfExitHandler;
 817|
 818| 
 819|/**************************************************************************
 820|  5-1. <<< [Errors_checkSum] チェックサムをかける >>> 
 821|【引数】
 822|  ・void**  ranges;  チェックするメモリの開始アドレスと終了の次のアドレスの配列
 823|  ・int  ranges_size;  ranges のメモリサイズ
 824|【補足】
 825|・プログラム領域や定数データ領域にチェックサムをかけて、プログラム(別タスク
 826|  のプログラム)によって不正なメモリ領域に書きこみアクセスしていないかを
 827|  チェックします。(読みこみはこの方法ではチェックできません)
 828|・ranges 引数の配列は、次のように格納します。
 829|  void*  ranges[] = {
 830|    (void*)0x00001000,  (void*)0x0x00010000,  // 範囲1、開始と終了
 831|    (void*)0x00021000,  (void*)0x0x00030000,  // 範囲2、開始と終了
 832|  };
 833|  終了アドレスのデータはチェックサムにかからないので注意してください。
 834|  再コンパイルしてメモリマップが変わる可能性があることに注意してください。
 835|・チェックサムに引っかかったら、エラーになります。
 836|  エラーメッセージには、正しいチェックサムの値が記述されています。
 837|  (設定によっては、参照するのにデバッグツールが必要です)
 838|・定数を変えて再コンパイルすると、プログラムのチェックサムが変わるので、
 839|  デバッガ上で正しいチェックサムの値を格納するグローバル変数 Errors_sum
 840|  を設定してください。
 841|・チェックサムが引っかかった場所を特定するには、デバッガでそのメモリ領域
 842|  全体を比較して行います。ただし、その際、メモリダンプをファイルに落とす
 843|  必要が起きるかも知れません。
 844|・チェックサムは、メモリ領域を unsigned char の配列と見て、int 型の
 845|  合計値に加算して計算しています。ただし、合計値の初期値は 0です。
 846|***************************************************************************/
 847|int   Errors_sum;  /* 正しいチェックサムの値 */
 848|
 849|void  Errors_checkSum( void** ranges, int ranges_size )
 850|{
 851|  int  sum = 0;
 852|  void**  ranges_over = (void**)( (char*)ranges + ranges_size );
 853|
 854|  while ( ranges < ranges_over ) {
 855|
 856|    unsigned char*  s;
 857|    unsigned char*  e;
 858|
 859|    s = (unsigned char*)*ranges;  ranges++;
 860|    e = (unsigned char*)*ranges;  ranges++;
 861|    for ( ; s < e; s++ )   sum += (int)*s;
 862|  }
 863|
 864|  if ( sum != Errors_sum ) {
 865|    #if  (((0)))
 866|      Errors_printf(
 867|        "CheckSum ERROR run_sum = %d(0x%08X), right_sum = %d(0x%08X)",
 868|         sum, sum, Errors_sum, Errors_sum );
 869|    #endif
 870|    error2_4( Errors_BadCheckSum,
 871|        "CheckSum ERROR run_sum = %d(0x%08X), right_sum = %d(0x%08X)",
 872|         sum, sum, Errors_sum, Errors_sum );
 873|  }
 874|}
 875|
 876| 
 877|/**********************************************************************
 878|  5-2. <<< [Errors_InitChk_imp] 初期化チェックの実装 >>> 
 879|【補足】
 880|・ERRORS_INITCHK の実装部です。
 881|・マジックナンバーをチェックして、初期化しているかどうか判定します。
 882|・bCountUp は、同じ order のとき、内部でカウントするかどうかです。
 883|【内部補足】
 884|・チェックは、ERRORS_INITCHK_MAGIC マクロによって暗号化された値が
 885|  正しいかどうかによって行います。
 886|**********************************************************************/
 887|#ifndef  NDEBUG
 888|void  Errors_InitChk_imp( void* parent, Errors_InitChk* m,
 889|  int order, const char* file, int line, bool bCountUp )
 890|{
 891|  ASSERT( parent != NULL );
 892|
 893|  /* 初期化関数で行うチェック */
 894|  if ( order == 0 ) {
 895|    m->key = line;
 896|    m->order = 0;
 897|    m->count = 1;
 898|  }
 899|
 900|  /* 一般の関数で行うチェック */
 901|  else {
 902|    if ( m->var != ERRORS_INITCHK_CANCELER_NUM ) {
 903|
 904|      /* マジックナンバーのチェック */
 905|      #ifndef  NDEBUG
 906|      if ( m->var !=
 907|          ERRORS_INITCHK_MAGIC( m, m->order, m->key, m->count ) ) {
 908|        error2_2( Errors_InitMiss,
 909|          "ERROR in %s(%d) : no init or out of scope", file, line );
 910|      }
 911|      #endif
 912|
 913|      /* 手続きオーダーのチェック */
 914|      #ifndef  NDEBUG
 915|      if ( order > m->order + m->count ) {
 916|        error2_4( Errors_OrderMiss,
 917|        "ERROR in %s(%d) : func order mistake\r\n"
 918|        "Current Order = %d ( count %d )",
 919|        file, line, m->order, m->count );
 920|      }
 921|      #endif
 922|    }
 923|
 924|    if ( order == m->order ) {
 925|      if ( bCountUp )
 926|        m->count ++;
 927|    }
 928|    else if ( order > m->order ) {
 929|      m->order = order;
 930|      m->count = 1;
 931|    }
 932|  }
 933|
 934|  /* マジックナンバーを作る */
 935|  m->var = ERRORS_INITCHK_MAGIC( m, m->order, m->key, m->count );
 936|}
 937|#endif  /* not NDEBUG */
 938|
 939|
 940| 
 941|/**********************************************************************
 942|  5-3. <<< [Errors_InitChk_print_imp] 初期化チェックのデバッグ表示の実装 >>> 
 943|**********************************************************************/
 944|#ifndef  ERRORS_CUT_DEBUG_TOOL
 945|void  Errors_InitChk_print_imp( Errors_InitChk* m, int order )
 946|{
 947|  Errors_printf( "&__initchk = %p, var = %08X, now-magic = %08X, culc-magic = %08X",
 948|    m, m->var,
 949|    ERRORS_INITCHK_MAGIC( m, order, m->key, m->count ),
 950|    ERRORS_INITCHK_MAGIC( m, m->order, m->key, m->count ) );
 951|}
 952|#endif
 953|
 954|
 955| 
 956|/***************************************************************************
 957|  5-4. <<< [Errors_FinishChk_count] 後始末カウンタを変更する >>> 
 958|  5-5. <<< [後始末カウンタ] >>>
 959|【引数】
 960|  ・char*  name;    後始末関数名
 961|  ・int    plus;    後始末カウンタを変更する増減分
 962|【補足】
 963|・後始末カウンタは、オブジェクトを生成したときに−1して、破壊したときに
 964|  +1するカウンタです。
 965|****************************************************************************/
 966|#ifdef  USES_ARRX
 967|#ifdef  USES_OFFSET
 968|#ifndef  ERRORS_CUT_DEBUG_TOOL
 969|
 970|ArrX_Buf  Errors_Fin_buf = { NULL, NULL, NULL };
 971|Errors_FinElem  Errors_Fin_bufX[ERRORS_FINISHCHK_MCLASS*2];
 972|Offset_Key  Errors_Fin_key;
 973|
 974|bool       Errors_FinishChk_bInit = false;
 975|ArrX_Able  Errors_FinishChk_ptrs;
 976|ArrX_AbleElemP   Errors_FinishChk_ptrsX[ERRORS_FINISHCHK_INSPECT_MOBJ];
 977|
 978|
 979|void  Errors_FinishChk_count( void (*_finish)(), char* name, int plus )
 980|{
 981|  int  fin = (int)_finish;
 982|  Errors_FinElem*  elem;
 983|
 984|  /* 初めての場合、Errors_Fin_buf を初期化する */
 985|  if ( Errors_Fin_buf.first == NULL ) {
 986|    ArrX_Buf_init( &Errors_Fin_buf,
 987|      Errors_Fin_bufX, sizeof(Errors_Fin_bufX) );
 988|    Offset_Key_init( &Errors_Fin_key,
 989|      Errors_FinElem, funcAdr, Offset_Int, Offset_NoDirec );
 990|  }
 991|
 992|  /* 後始末関数のアドレスに対応する要素を検索する */
 993|  elem = ArrX_Buf_search_i( &Errors_Fin_buf, &Errors_Fin_key,
 994|    fin, Errors_FinElem );
 995|  if ( elem == NULL ) {
 996|    elem = ArrX_Buf_alloc( &Errors_Fin_buf, Errors_FinElem );
 997|    strncpy( elem->name, name, ERRORS_FINISHCHK_MNAME );
 998|    elem->name[ERRORS_FINISHCHK_MNAME-1] = '\0';
 999|    elem->funcAdr = fin;
1000|  }
1001|
1002|  /* 後始末カウンタを変更する */
1003|  elem->count += plus;
1004|}
1005|
1006|#endif  /* not NDEBUG */
1007|#endif  /* USES_OFFSET */
1008|#endif  /* USES_ARRX */
1009|
1010|
1011| 
1012|/***************************************************************************
1013|  5-6. <<< [Errors_FinishChk_imp] すべてのオブジェクトが後始末されたかチェックする >>> 
1014|【補足】
1015|・チェックに引っかかっても error 関数を呼び出しません。
1016|****************************************************************************/
1017|#ifdef  USES_ARRX
1018|#ifdef  USES_OFFSET
1019|#ifndef  NDEBUG
1020|
1021|void  Errors_FinishChk_imp(void)
1022|{
1023|  static  int  count = 0;
1024|  Errors_FinElem*  elem;
1025|  ArrX_AbleElemP*  p;
1026|
1027|  count++;
1028|  if ( count >= 2 && Errors_bExiting ) {
1029|    Errors_printf_release( "デストラクタで FINISHCHK するときは、"
1030|      "#define  ERRORS_NO_EXIT_CHK を設定してください。" );
1031|  }
1032|
1033|  /* 後始末チェック */
1034|  for ( ArrX_Buf_forEach( &Errors_Fin_buf, &elem, Errors_FinElem ) ) {
1035|    if ( elem->count != 0 ) {
1036|      Errors_printf_release( "%s の後始末カウンタ= %+d",
1037|        elem->name, elem->count );
1038|    }
1039|  }
1040|
1041|  /* 後始末していないオブジェクトのアドレスを表示する */
1042|  if ( Errors_FinishChk_bInit && ArrX_Able_getN( &Errors_FinishChk_ptrs, ArrX_AbleElemP ) > 0 ) {
1043|    Errors_printf( "次のアドレスのオブジェクトは、まだ後始末されていません" );
1044|    Errors_printf( "Errors_FinishChk_addr マクロに指定し、"
1045|       " Errors_FinishChk_Inspect_forInit_imp 関数内にブレークポイントを張ってください。" );
1046|    for ( ArrX_Able_forEach( &Errors_FinishChk_ptrs, &p, ArrX_AbleElemP ) ) {
1047|      Errors_printf( "0x%08X", p->p );
1048|    }
1049|  }
1050|
1051|  /* StdPlus_chkFree のチェック */
1052|  #ifdef  USES_STDPLUS
1053|    StdPlus_chkFree();
1054|  #endif
1055|
1056|  /* チェックが行われたことを表示する */
1057|  Errors_printf_release( "Finish Chk Done." );
1058|}
1059|
1060|#endif  /* not NDEBUG */
1061|#endif  /* USES_OFFSET */
1062|#endif  /* USES_ARRX */
1063|
1064| 
1065|/***************************************************************************
1066|  5-7. <<< [Errors_FinishChk_print_imp] 指定の後始末カウンタを表示する >>> 
1067|****************************************************************************/
1068|#ifdef  USES_ARRX
1069|#ifdef  USES_OFFSET
1070|#ifndef  NDEBUG
1071|#ifndef  ERRORS_CUT_DEBUG_TOOL
1072|
1073|void  Errors_FinishChk_print_imp( const char* _finish, char* file, int line )
1074|{
1075|  Errors_FinElem*  elem;
1076|  bool  bDisp = false;
1077|
1078|  /* 後始末カウンタを表示する */
1079|  for ( ArrX_Buf_forEach( &Errors_Fin_buf, &elem, Errors_FinElem ) ) {
1080|    if ( strncmp( elem->name, _finish, ERRORS_FINISHCHK_MNAME - 1 ) == 0 ) {
1081|      Errors_printf( "後始末カウンタ %s (%+d) in %s(%d)",
1082|        elem->name, elem->count, file, line );
1083|      bDisp = true;  break;
1084|    }
1085|  }
1086|  if ( ! bDisp ) {
1087|    Errors_printf( "後始末カウンタ %s (%+d) in %s(%d) (It has not inited yet)",
1088|      _finish, elem->count, file, line );
1089|  }
1090|}
1091|
1092|#endif  /* not ERRORS_CUT_DEBUG_TOOL */
1093|#endif  /* not NDEBUG */
1094|#endif  /* USES_OFFSET */
1095|#endif  /* USES_ARRX */
1096|
1097| 
1098|/***************************************************************************
1099|  5-8. <<< [Errors_FinishChk_printAll] すべての後始末カウンタを表示する >>> 
1100|****************************************************************************/
1101|#ifdef  USES_ARRX
1102|#ifdef  USES_OFFSET
1103|#ifndef  NDEBUG
1104|#ifndef  ERRORS_CUT_DEBUG_TOOL
1105|
1106|void  Errors_FinishChk_printAll(void)
1107|{
1108|  Errors_FinElem*  elem;
1109|
1110|  Errors_printf( "後始末カウンタ一覧 :" );
1111|  for ( ArrX_Buf_forEach( &Errors_Fin_buf, &elem, Errors_FinElem ) ) {
1112|    Errors_printf( "%s (%+d)", elem->name, elem->count );
1113|  }
1114|}
1115|
1116|#endif  /* not ERRORS_CUT_DEBUG_TOOL */
1117|#endif  /* not NDEBUG */
1118|#endif  /* USES_OFFSET */
1119|#endif  /* USES_ARRX */
1120|
1121| 
1122|/***************************************************************************
1123|  5-9. <<< [Errors_FinishChk_Inspect_forInit_imp] 後始末を忘れたオブジェクトを調査する >>> 
1124|****************************************************************************/
1125|#if  defined(USES_ARRX) && defined(USES_OFFSET) && !defined(ERRORS_CUT_DEBUG_TOOL)
1126|
1127|#define  Errors_FinishChk_addr  0x00000000
1128|
1129|void  Errors_FinishChk_Inspect_forInit_imp( void* obj, void (*_finish)(),
1130|  const char* name )
1131|{
1132|  ArrX_AbleElemP*  p;
1133|
1134|  if ( obj == (void*)Errors_FinishChk_addr ) {
1135|    MARK();
1136|  }
1137|
1138|  /* オブジェクト・ストアを初期化する */
1139|  if ( ! Errors_FinishChk_bInit ) {
1140|    ArrX_Able_init( &Errors_FinishChk_ptrs, Errors_FinishChk_ptrsX,
1141|      sizeof(Errors_FinishChk_ptrsX), ArrX_AbleElemP );
1142|    Errors_FinishChk_bInit = true;
1143|  }
1144|
1145|  /* 二重初期化チェック */
1146|  for ( ArrX_Able_forEach( &Errors_FinishChk_ptrs, &p, ArrX_AbleElemP ) ) {
1147|    if ( p->p == obj )
1148|      break;
1149|  }
1150|  if ( p != ArrX_Able_getOver( &Errors_FinishChk_ptrs ) ) {
1151|
1152|    p = ArrX_Able_getFirstDisabled( &Errors_FinishChk_ptrs, ArrX_AbleElemP );
1153|    p->p = obj;
1154|    ArrX_AbleElem_setAble( p, true );
1155|
1156|    error2_1( Errors_Err_DoubleInit, "二重初期化、または開放し忘れ (addr = %p)", obj );
1157|  }
1158|
1159|  /* オブジェクトを登録する */
1160|  p = ArrX_Able_getFirstDisabled( &Errors_FinishChk_ptrs, ArrX_AbleElemP );
1161|  p->p = obj;
1162|  ArrX_AbleElem_setAble( p, true );
1163|
1164|
1165|  /* 後始末カウンタとの整合性をチェックする */
1166|  #if 0
1167|  {
1168|    Errors_FinElem*  elem;
1169|    int  fin = (int)_finish;
1170|
1171|    elem = ArrX_Buf_search_i( &Errors_Fin_buf, &Errors_Fin_key,
1172|      fin, Errors_FinElem );
1173|    if ( elem == NULL ) {
1174|      elem = ArrX_Buf_alloc( &Errors_Fin_buf, Errors_FinElem );
1175|      strncpy( elem->name, name, ERRORS_FINISHCHK_MNAME );
1176|      elem->name[ERRORS_FINISHCHK_MNAME-1] = '\0';
1177|      elem->funcAdr = fin;
1178|    }
1179|    if ( elem->count != ArrX_Able_getN( &Errors_FinishChk_ptrs, ArrX_AbleElemP ) ) {
1180|      Errors_printf( "FinishChk  count1 = %d, count2 = %d",
1181|        elem->count, ArrX_Able_getN( &Errors_FinishChk_ptrs, ArrX_AbleElemP ) );
1182|      Errors_break( 0x4141 );
1183|    }
1184|  }
1185|  #else
1186|    name, _finish;  /* avoid warning */
1187|  #endif
1188|}
1189|#endif
1190|
1191| 
1192|/***************************************************************************
1193|  5-10. <<< [Errors_FinishChk_Inspect_forFinish_imp] 後始末を忘れたオブジェクトを調査する >>> 
1194|****************************************************************************/
1195|#if  defined(USES_ARRX) && defined(USES_OFFSET) && !defined(ERRORS_CUT_DEBUG_TOOL)
1196|
1197|void  Errors_FinishChk_Inspect_forFinish_imp( void* obj, void (*_finish)(),
1198|  const char* name )
1199|{
1200|  ArrX_AbleElemP*  p = (ArrX_AbleElemP*)ArrX_Able_getOver( &Errors_FinishChk_ptrs );
1201|
1202|  if ( obj == (void*)Errors_FinishChk_addr ) {
1203|    MARK();
1204|  }
1205|
1206|  /* オブジェクトを登録からはずす */
1207|  for ( ArrX_Able_forEach( &Errors_FinishChk_ptrs, &p, ArrX_AbleElemP ) ) {
1208|    if ( p->p == obj ) {
1209|      ArrX_AbleElem_setAble( p, false );
1210|      break;
1211|    }
1212|  }
1213|
1214|  /* 二重後始末チェック */
1215|  if ( p == ArrX_Able_getOver( &Errors_FinishChk_ptrs ) ) {
1216|    error2_1( Errors_Err_NoInit, "初期化関数に ERRORS_FINISHCHK_INSPECT_FOR_INIT "
1217|      "が抜けているか、2重開放か、無効なアドレスです。 (addr = %p)", obj );
1218|  }
1219|
1220|  /* 後始末カウンタとの整合性をチェックする */
1221|  #if 0
1222|  {
1223|    Errors_FinElem*  elem;
1224|    int  fin = (int)_finish;
1225|
1226|    elem = ArrX_Buf_search_i( &Errors_Fin_buf, &Errors_Fin_key,
1227|      fin, Errors_FinElem );
1228|    if ( elem == NULL ) {
1229|      elem = ArrX_Buf_alloc( &Errors_Fin_buf, Errors_FinElem );
1230|      strncpy( elem->name, name, ERRORS_FINISHCHK_MNAME );
1231|      elem->name[ERRORS_FINISHCHK_MNAME-1] = '\0';
1232|      elem->funcAdr = fin;
1233|    }
1234|    Errors_printf( "FinishChk  count1 = %d, count2 = %d",
1235|      elem->count, ArrX_Able_getN( &Errors_FinishChk_ptrs, ArrX_AbleElemP ) );
1236|    if ( elem->count != ArrX_Able_getN( &Errors_FinishChk_ptrs, ArrX_AbleElemP ) ) {
1237|      Errors_break( 0x4141 );
1238|      error();
1239|    }
1240|  }
1241|  #else
1242|    name, _finish;  /* avoid warning */
1243|  #endif
1244|}
1245|#endif
1246|
1247| 
1248|/***********************************************************************
1249|  5-11. <<< [Errors_setStart_imp] 初期設定値を変更する >>> 
1250|【引数】
1251|  ・int   r6;    初期設定値
1252|  ・int*  r7;    初期設定変数
1253|【補足】
1254|・デバッガで、r6 を修正することで、*r7 の値を設定します。
1255|・再コンパイルしなくても初期値を変更することができます。
1256|************************************************************************/
1257|void  Errors_setStart_imp( int r6, int* r7 )
1258|{
1259|  *r7 = r6;
1260|}
1261|
1262| 
1263|/*--------------------------------------------------------------------*/
1264|/* 6. <<<<◆ デバッグツール >>>> */ 
1265|/*--------------------------------------------------------------------*/
1266|
1267|char*  Errors_ps = "%s";
1268|char*  Errors_ns = "";
1269|char*  Errors_eu = "Errors_Unofficial";
1270|char*  Errors_ea = "Errors_ASSERT";
1271|char*  Errors_null = "(e-null)";
1272|
1273|char*  Errors_printToMemory( const char* msg );
1274|void   Errors_printToConsole( const char* msg );
1275|void   Errors_printToWindows( const char* msg );
1276|void   Errors_printToFile( const char* msg );
1277|void   Errors_printToPB( const char* msg );
1278|
1279|#if !defined(NDEBUG) || defined(ERRORS_ERROR_REPORT)
1280| char*  Errors_appName = NULL;
1281| char*  Errors_appVersion = NULL;
1282| struct HWND__* Errors_parentWnd = NULL;
1283| void*  Errors_parentCWnd = NULL;  /* CWnd* 型にキャストして使う */
1284|#endif
1285|
1286|#ifdef  ERRORS_PRINTF_TO_FILE
1287|  #ifndef  USES_FILEX
1288|    #error  Need FileX if define ERRORS_PRINTF_TO_FILE
1289|  #endif
1290|#endif
1291| 
1292|/***************************************************************************
1293|  6-1. <<< [Errors_backmark_imp] BACKMARK の関数部 >>> 
1294|****************************************************************************/
1295|#if  defined(ERRORS_USE_BACKMARK) && defined(USES_FILEX) && defined(ERRORS_PRINTF_TO_FILE)
1296|void  Errors_backmark_imp( const char* file, int line )
1297|{
1298|  char  s[_MAX_PATH + 20];
1299|
1300|  sprintf( s, "MARK %s(%d)", file, line );
1301|  Errors_printToFile( s );
1302|}
1303|#endif
1304|
1305| 
1306|/***************************************************************************
1307|  6-2. <<< [Errors_counter_imp] カウンタ、この関数の呼び出し回数を数えます。 >>> 
1308|【引数】
1309|  ・int  stop_count; 返り値を 1 にする呼び出し回数
1310|  ・int  返り値;     カウンタが stop_count になると 1(not=0)
1311|【補足】
1312|・最新版の COUNT マクロを使用してください。
1313|・回数を数えたい実行経路に置きます。
1314|・その経路を通る回数を調べるときは、引数 stop_count を 0 にして、
1315|  実行後、グローバル変数 Errors_count を参照します。
1316|・指定された回数呼び出されると返り値が0以外になるので、
1317|  それを判断して、ブレークポイント(brk)を付けたりします。
1318|【例】
1319|・stop_count==3 なら、返り値は 1,2,0,1,2,0,1,2,0....
1320|・if ( Errors_counter(0) )
1321|     { int i;  i++; }        ... ここにブレークポイントを張る
1322|****************************************************************************/
1323|int  Errors_count = 0;
1324|int  Errors_count0 = 0;
1325|
1326|char*  Errors_count_prev_n_file;
1327|int    Errors_count_prev_n_line;
1328|int    Errors_count_prev_n;
1329|
1330|int  Errors_count2 = 0;
1331|int  Errors_count2_0 = 0;
1332|
1333|char*  Errors_count2_prev_n_file;
1334|int    Errors_count2_prev_n_line;
1335|int    Errors_count2_prev_n;
1336|
1337|int  Errors_count_b = 1;
1338|int  Errors_count_b2 = 1;
1339|
1340|#if 0
1341|int  Errors_counter_imp( int stop_count )
1342|{
1343|  Errors_count ++;
1344|  return  ( stop_count > 0 &&
1345|       Errors_count % stop_count == 0 );
1346|}
1347|#endif
1348| 
1349|/**************************************************************************
1350|  6-3. <<< [Errors_WD_imp] WD の実装 >>> 
1351|***************************************************************************/
1352|#ifndef  ERRORS_CUT_DEBUG_TOOL
1353|void  Errors_WD_imp( char* name, void* p, int ver,
1354|  char* file, int line )
1355|{
1356|  Errors_printf( "%s (%p) = %d(0x%X) \'%c\' : %s(%d)",
1357|    name, p, ver, ver, Errors_getDispCh( ver ), file, line );
1358|}
1359|#endif
1360| 
1361|/**************************************************************************
1362|  6-4. <<< [Errors_WSP_imp] WSP の実装 >>> 
1363|***************************************************************************/
1364|#ifndef  ERRORS_CUT_DEBUG_TOOL
1365|void  Errors_WSP_imp( char* name, const char** p, const char* ver,
1366|  char* file, int line )
1367|{
1368|  enum { s_size = 20 };
1369|  char  s[s_size];
1370|  char*  sp;
1371|  char*  sp_over = s + s_size - 1;
1372|  const char*  vp;
1373|
1374|  for ( sp = s, vp = ver; sp < sp_over; sp++, vp++ ) {
1375|    *sp = Errors_getDispCh( *vp );
1376|  }
1377|  *sp = '\0';
1378|
1379|  Errors_printf( "%s (%p) = %p \"%s\" : %s(%d)", name, p, ver, s, file, line );
1380|}
1381|#endif
1382| 
1383|/**************************************************************************
1384|  6-5. <<< [Errors_WX_imp] WX の実装 >>> 
1385|***************************************************************************/
1386|#ifndef  ERRORS_CUT_DEBUG_TOOL
1387|void  Errors_WX_imp( char* adr_name, void* adr, int size, char* file, int line )
1388|{
1389|  unsigned char*  p = (unsigned char*)adr;
1390|  unsigned char*  p_over = (unsigned char*)adr + size;
1391|  unsigned char*  cp;
1392|  unsigned char*  cp_over;
1393|  char*  sp;
1394|  char   sline[256];
1395|
1396|  if ( size < 0x10 ) {
1397|    sp = sline;
1398|    sprintf( sp, "%s(%08X)  %08X : ", adr_name, adr, p );  sp = strchr( sp, '\0' );
1399|    for ( cp = p; cp < p_over; cp++ ) {
1400|      if ( cp >= p && cp < p_over ) {
1401|        sprintf( sp, "%02X%s", *cp,
1402|          ((int)(cp - p) & 0x3) == 3 && cp < p_over - 1  ? " - " : " " );
1403|      }
1404|      else  sprintf( sp, "   " );
1405|      sp = strchr( sp, '\0' );
1406|    }
1407|    for ( cp = p; cp < p_over; cp++ ) {
1408|      if ( cp >= p && cp < p_over )  sprintf( sp, "%c", Errors_getDispCh( *cp ) );
1409|      else  sprintf( sp, " " );
1410|      sp++;
1411|    }
1412|    sprintf( sp, ": %s(%d)", file, line );
1413|    Errors_printf( "%s", sline );
1414|  }
1415|  else {
1416|    Errors_printf( "%s(%08X) : size = %d(0x%X) : %s(%d)", adr_name, adr,
1417|      size, size, file, line );
1418|    for ( ; p < p_over; p += 0x10 ) {
1419|      if ( p >= (unsigned char*)adr + 0x10 * ERRORS_WX_NLINE &&
1420|           p < p_over - 0x10 * ERRORS_WX_NLINE ) {
1421|        if ( p == (unsigned char*)adr + 0x10 * ERRORS_WX_NLINE )
1422|          Errors_printf( " : " );
1423|        continue;
1424|      }
1425|      sp = sline;
1426|      sprintf( sp, "%s  %08X : ", adr_name, p );  sp = strchr( sp, '\0' );
1427|      cp_over = p + 0x10;
1428|      for ( cp = p; cp < cp_over; cp++ ) {
1429|        if ( cp >= p && cp < p_over ) {
1430|          sprintf( sp, "%02X%s", *cp,
1431|            ((int)cp & 0x3) == 3 && cp < cp_over - 1  ? " - " : " " );
1432|        }
1433|        else  sprintf( sp, "   " );
1434|        sp = strchr( sp, '\0' );
1435|      }
1436|      for ( cp = p; cp < cp_over; cp++ ) {
1437|        if ( cp >= p && cp < p_over )  sprintf( sp, "%c", Errors_getDispCh( *cp ) );
1438|        else  sprintf( sp, " " );
1439|        sp++;
1440|      }
1441|      Errors_printf( "%s", sline );
1442|    }
1443|  }
1444|}
1445|#endif
1446| 
1447|/**************************************************************************
1448|  6-6. <<< [Errors_WX2_imp] WX2 の実装 >>> 
1449|***************************************************************************/
1450|#ifndef  ERRORS_CUT_DEBUG_TOOL
1451|void  Errors_WX2_imp( char* adr_name, void* adr, int size, char* file, int line )
1452|{
1453|  unsigned char*  p = (unsigned char*)( (int)adr & 0xFFFFFFF0 );
1454|  unsigned char*  p_over = (unsigned char*)( ((int)adr + size + 0xF) & 0xFFFFFFF0 );
1455|  unsigned char*  adr_over = (unsigned char*)adr + size;
1456|  unsigned char*  cp;
1457|  unsigned char*  cp_over;
1458|  char*  sp;
1459|  char   sline[80];
1460|
1461|  if ( p_over - p == 0x10 ) {
1462|    sp = sline;
1463|    sprintf( sp, "%s(%08X)  %08X : ", adr_name, adr, p );  sp = strchr( sp, '\0' );
1464|    for ( cp = p; cp < p_over; cp++ ) {
1465|      if ( cp >= (unsigned char*)adr && cp < adr_over )
1466|        sprintf( sp, "%02X%s", *cp, ((int)cp & 0x3) == 3 ? " - " : " " );
1467|      else  sprintf( sp, "   " );
1468|      sp = strchr( sp, '\0' );
1469|    }
1470|    sprintf( sp, ": %s(%d)", file, line );
1471|    Errors_printf( "%s", sline );
1472|  }
1473|  else {
1474|    Errors_printf( "%s(%08X) : size = %d(0x%X) : %s(%d)", adr_name, adr,
1475|      size, size, file, line );
1476|    for ( ; p < p_over; p += 0x10 ) {
1477|      sp = sline;
1478|      sprintf( sp, "%s  %08X : ", adr_name, p );  sp = strchr( sp, '\0' );
1479|      cp_over = p + 0x10;
1480|      for ( cp = p; cp < cp_over; cp++ ) {
1481|        if ( cp >= (unsigned char*)adr && cp < adr_over )
1482|          sprintf( sp, "%02X%s", *cp, ((int)cp & 0x3) == 3 ? " - " : " " );
1483|        else  sprintf( sp, "   " );
1484|        sp = strchr( sp, '\0' );
1485|      }
1486|      Errors_printf( "%s", sline );
1487|    }
1488|  }
1489|}
1490|#endif
1491| 
1492|/**************************************************************************
1493|  6-7. <<< [Errors_setWATCH_imp, Errors_WATCH_imp] WATCH, setWATCH の実装 >>> 
1494|***************************************************************************/
1495|#ifndef  ERRORS_CUT_DEBUG_TOOL
1496|void*  Errors_WATCH_adr = NULL;
1497|int    Errors_WATCH_size = 0;
1498|int    Errors_WATCH_type = Errors_WATCH_Bin;
1499|char   Errors_WATCH_prevData[256];
1500|bool   Errors_bWatchLookAtCount;
1501|
1502|void  Errors_setWATCH_imp( void* adr, char* name, int type, int size,
1503|  bool lookAtCount, char* file, int line )
1504|{
1505|  enum { n = 4 };
1506|  enum { s_size = n*(sizeof(int)*2+1) };
1507|  char  s[s_size];
1508|  char*  adr_over;
1509|  char*  prev = Errors_WATCH_prevData;
1510|  char*  sp;
1511|  const int*  pp;
1512|  const int*  pp_over;
1513|
1514|  ASSERT( size <= (int)sizeof( Errors_WATCH_prevData ) );
1515|  ASSERT( type == Errors_WATCH_Bin || type == Errors_WATCH_CharP );
1516|  Errors_WATCH_adr = adr;
1517|  Errors_WATCH_size = size;
1518|  Errors_WATCH_type = type;
1519|  Errors_bWatchLookAtCount = lookAtCount;
1520|
1521|  if ( adr == NULL ) {
1522|    Errors_printf( "first WATCH!★ : %s (adr = NULL, size = 0x%X) : %s(%d)", name, size, file, line );
1523|  }
1524|  else {
1525|    if ( type == Errors_WATCH_Bin ) {
1526|      memcpy( prev, adr, size );
1527|      adr_over = (char*)adr + size;
1528|      for ( ; (char*)adr < adr_over; adr = (char*)adr + n*8 ) {
1529|        pp_over = (int*)adr + n;
1530|        for ( pp = (const int*)adr, sp = s; pp < pp_over; pp++ ) {
1531|          sprintf( sp, "%08X", *pp );
1532|          sp += 8;  *sp = ' ';  sp ++;
1533|        }
1534|        *(sp - 1) = '\0';
1535|        Errors_printf( "first WATCH!★ : %s (adr = %p, size = 0x%X) : %s : %s(%d)",
1536|          name, adr, size, s, file, line );
1537|      }
1538|    }
1539|    else { ASSERT( type == Errors_WATCH_CharP );
1540|      strncpy( prev, (char*)adr, sizeof( Errors_WATCH_prevData ) );
1541|      Errors_printf( "first WATCH!★ : %s (adr = %p) : %s : %s(%d)",
1542|          name, adr, adr, file, line );
1543|    }
1544|  }
1545|}
1546|
1547|void  Errors_WATCH_imp( char* file, int line )
1548|{
1549|  enum { n = 4 };
1550|  enum { s_size = n*(sizeof(int)*2+1) };
1551|  char  s[s_size];
1552|  char*  adr = (char*)Errors_WATCH_adr;
1553|  char*  adr_over;
1554|  int    size = Errors_WATCH_size;
1555|  char*  prev = Errors_WATCH_prevData;
1556|  char*  sp;
1557|  const int*  pp;
1558|  const int*  pp_over;
1559|  int   f;
1560|  bool  bChg = false;
1561|
1562|  if ( adr == NULL ) {
1563|    Errors_printf( "WATCH : no change : %s(%d)", file, line );
1564|    return;
1565|  }
1566|
1567|  if ( Errors_WATCH_type == Errors_WATCH_Bin ) {
1568|    adr_over = adr + size;
1569|    for ( ; adr < adr_over; adr += n*8 ) {
1570|      if ( adr_over - adr > n*8 )   f = memcmp( prev, adr, n*8 );
1571|      else   f = memcmp( prev, adr, adr_over - adr );
1572|
1573|      if ( f != 0 ) {
1574|        pp_over = (int*)adr + n;
1575|        for ( pp = (const int*)adr, sp = s; pp < pp_over; pp++ ) {
1576|          sprintf( sp, "%08X", *pp );
1577|          sp += 8;  *sp = ' ';  sp ++;
1578|        }
1579|        *(sp - 1) = '\0';
1580|        Errors_printf( "WATCH!★ : adr = %p : %s : %s(%d)", adr, s, file, line );
1581|        bChg = true;
1582|      }
1583|    }
1584|    memcpy( prev, Errors_WATCH_adr, size );
1585|  }
1586|  else {  ASSERT( Errors_WATCH_type == Errors_WATCH_CharP );
1587|    if ( strncmp( prev, adr, sizeof(Errors_WATCH_prevData) ) != 0 ) {
1588|      Errors_printf( "WATCH!★ : adr = %p : %s : %s(%d)",
1589|          adr, adr, file, line );
1590|      bChg = true;
1591|    }
1592|    strncpy( prev, adr, sizeof( Errors_WATCH_prevData ) );
1593|  }
1594|
1595|  if ( ! bChg )
1596|    Errors_printf( "WATCH : no change : %s(%d)", file, line );
1597|}
1598|#endif
1599|
1600| 
1601|/***************************************************************************
1602|  6-8. <<< [Errors_log] デバッグ表示の記録(ログ)>>> 
1603|  6-9. <<< [Errors_log2] エラーメッセージの記録(ログ)>>>
1604|【補足】
1605|・エラーが発生したり、ブレークしたりすると、Errors_printf_flush 関数に
1606|  よって、このログの内容がファイルに出力されます。(ファイルシステムを
1607|  装備している場合)
1608|・ログの容量が足らない場合、errors_log の配列要素数を増やしてください。
1609|  それでも、増えないと感じた場合、ビューアに取り込むサイズを確認してください。
1610|・ログの容量を越えて記録した場合、もう一度ログの最初から記録を開始します。
1611|  最初に戻る前にブレークさせることもできます。(→bf2 関数)
1612|****************************************************************************/
1613|char  Errors_log[Errors_log_size];
1614|char* Errors_log_p = Errors_log;
1615|int   Errors_LogTop_iPage = 1;
1616|
1617|char  Errors_log2[0x777];
1618|char* Errors_log2_p = Errors_log2;
1619|
1620|char  Errors_log_testCase[1024];
1621|
1622|char*  Errors_poolStart = NULL;  /* ため始める位置、Errors_log へのポインタ */
1623|                                 /* NULL=ためていない */
1624|
1625|
1626| 
1627|/**************************************************************************
1628|  6-10. <<< [Errors_printf_imp] デバッグ用 printf >>> 
1629|【引数】
1630|  ・printf と同じ
1631|  ・char*  返り値;   今回のメッセージの文字列先頭アドレス(ログの中)
1632|【補足】
1633|・Errors_printf の実装部分です
1634|・デバッグするときに使います。リリース版でも使えます。
1635|・デバッグが終了したら ERRORS_CUT_DEBUG_TOOL を設定してコンパイルすれば、
1636|  容易にすべてのデバッグツールをカットすることができます。
1637|・メモリに表示しない場合、返り値は NULL です。
1638|・どのような表示媒体を使用するかは、ERRORS_PRINTF_TO_WINDOW などの
1639|  設定によります。
1640|***************************************************************************/
1641|char*  Errors_printf_imp( const char* fmt, ... )
1642|{
1643|  char*  ret;
1644|  va_list  va;
1645|
1646|  va_start( va, fmt );
1647|  ret = Errors_printf_imp2( fmt, va );
1648|  va_end( va );
1649|
1650|  return  ret;
1651|}
1652|
1653|
1654| 
1655|/**************************************************************************
1656|  6-11. <<< [Errors_printf_imp2] Errors_printf_imp のサブルーチン >>> 
1657|***************************************************************************/
1658|char*  Errors_printf_imp2( const char* fmt, va_list va )
1659|{
1660|  #ifdef  ERRORS_PRINTF_TO_MEMORY
1661|    char*  ret;
1662|  #else
1663|    char*  ret = NULL;
1664|  #endif
1665|  char  msg[8192];
1666|
1667|  if ( ! Errors_printfFlag )  return  NULL;
1668|
1669|  vsprintf( msg, fmt, va );
1670|  if ( strlen( msg ) > sizeof(msg) ) {
1671|    strcpy( msg + sizeof(msg) - 5, "..." );
1672|    bf( Errors_ErrValue, 0, (int)__FILE__, __LINE__ );
1673|    Errors_printLowLevel( "Errors_printf msg block was over." );
1674|    Errors_exit( __FILE__,__LINE__ );
1675|  }
1676|
1677|  #ifdef  ERRORS_PRINTF_TO_WINDOW
1678|    if ( Errors_poolStart == NULL )
1679|      Errors_printToWindows( msg );
1680|  #endif
1681|
1682|  #ifdef  ERRORS_PRINTF_TO_STDOUT
1683|    Errors_printToConsole( msg );
1684|  #endif
1685|
1686|  #ifdef  ERRORS_PRINTF_TO_STDERR
1687|    fprintf( stderr, "%s\r\n", msg );
1688|  #endif
1689|
1690|  #ifdef  ERRORS_PRINTF_TO_FILE
1691|    Errors_printToFile( msg );
1692|  #endif
1693|
1694|  #ifdef  ERRORS_PRINTF_TO_MEMORY
1695|    ret = Errors_printToMemory( msg );
1696|  #else
1697|    #ifndef  NDEBUG
1698|      if ( Errors_poolStart != NULL ) {
1699|        static  int  f = 0;
1700|
1701|        f++;
1702|        if ( f == 1 )
1703|        Errors_printLowLevel( "エラーメッセージを格納する ERRORS_PRINTF_TO_MEMORY の設定が必要です。" );
1704|      }
1705|    #endif
1706|  #endif
1707|
1708|  #ifdef  ERRORS_PRINTF_TO_PB
1709|    Errors_printToPB( msg );
1710|  #endif
1711|
1712|  return  ret;
1713|}
1714|
1715|
1716| 
1717|/**************************************************************************
1718|  6-12. <<< [Errors_printf_back_imp] Errors_printf_back の関数部 >>> 
1719|***************************************************************************/
1720|#if  defined(ERRORS_USE_BACKMARK) && defined(USES_FILEX) && defined(ERRORS_PRINTF_TO_FILE)
1721|void  Errors_printf_back_imp( const char* fmt, ... )
1722|{
1723|  va_list  va;
1724|  char  msg[8192];
1725|
1726|  va_start( va, fmt );
1727|  vsprintf( msg, fmt, va );
1728|  va_end( va );
1729|
1730|  Errors_printToFile( msg );
1731|}
1732|#endif
1733| 
1734|/***************************************************************************
1735|  6-13. <<< [Errors_printfFlag] 表示フラグ >>> 
1736|【補足】
1737|・参考:Errors_setPrintfFlag, Errors_breakFlag
1738|****************************************************************************/
1739|bool  Errors_printfFlag = true;  /* 表示フラグ */
1740|bool  Errors_bPrintFileFirst = true;
1741|char* Errors_fileName = "errlog.txt";
1742| 
1743|/**************************************************************************
1744|  6-14. <<< [Errors_printf_release] リリース用エラー printf >>> 
1745|【補足】
1746|・リリースするプログラムの標準的なエラー表示に使います。
1747|***************************************************************************/
1748|char*  Errors_printf_release( const char* fmt, ... )
1749|{
1750|  char  msg[1024];
1751|  va_list  va;
1752|  #ifdef  ERRORS_ERR_PRINTF_TO_MEMORY
1753|    char*  ret;
1754|  #else
1755|    char*  ret = NULL;
1756|  #endif
1757|
1758|  va_start( va, fmt );
1759|  vsprintf( msg, fmt, va );
1760|  if ( strlen( msg ) > sizeof(msg) ) {
1761|    strcpy( msg + sizeof(msg) - 4, "..." );
1762|    bf( Errors_ErrValue, 0, (int)__FILE__, __LINE__ );
1763|  }
1764|  va_end( va );
1765|
1766|  #ifdef  ERRORS_ERR_PRINTF_TO_WINDOW
1767|    if ( Errors_poolStart == NULL )
1768|      Errors_printToWindows( msg );
1769|  #endif
1770|
1771|  #ifdef  ERRORS_ERR_PRINTF_TO_STDOUT
1772|    Errors_printToConsole( msg );
1773|  #endif
1774|  #ifdef  ERRORS_ERR_PRINTF_TO_STDERR
1775|    fprintf( stderr, "%s\r\n", msg );
1776|  #endif
1777|
1778|  #if defined(ERRORS_ERR_PRINTF_TO_FILE) && ! defined(ERRORS_CUT_DEBUG_TOOL)
1779|    Errors_printToFile( msg );
1780|  #endif
1781|
1782|  #ifdef  ERRORS_ERR_PRINTF_TO_MEMORY
1783|    ret = Errors_printToMemory( msg );
1784|  #else
1785|    #ifndef  NDEBUG
1786|      if ( Errors_poolStart != NULL ) {
1787|        static  int  f = 0;
1788|
1789|        f++;
1790|        if ( f == 1 )
1791|          Errors_printLowLevel( "エラーメッセージを格納する ERRORS_ERR_PRINTF_TO_MEMORY の設定が必要です。" );
1792|      }
1793|    #endif
1794|  #endif
1795|
1796|  #ifdef  ERRORS_ERR_PRINTF_TO_PB
1797|    Errors_printToPB( msg );
1798|  #endif
1799|
1800|  return  ret;
1801|}
1802|
1803|
1804| 
1805|/**************************************************************************
1806|  6-15. <<< [Errors_errPrintf] テストエラー用 printf >>> 
1807|【補足】
1808|・通常の Errors_printf の出力が多すぎるときに、通常とは別のバッファに
1809|  テスト・プログラムのエラー表示を行うときに使います。
1810|・前回の Errors_testCasePrintf で登録されたテストケース情報を
1811|  出力してから、本関数の引数を出力します。
1812|・変数 Errors_log2(errlog2.txt ファイル) に出力されます。
1813|  ただし、ファイルに出力する場合は、ERRORS_PRINTF_FLUSH を使います。
1814|・Errors_log にも出力します。
1815|***************************************************************************/
1816|char*  Errors_errPrintf( const char* fmt, ... )
1817|{
1818|  char  msg[1024];
1819|  va_list  va;
1820|  char*  ret;
1821|
1822|  va_start( va, fmt );
1823|  vsprintf( msg, fmt, va );
1824|  if ( strlen( msg ) > sizeof(msg) ) {
1825|    strcpy( msg + sizeof(msg) - 4, "..." );
1826|    bf( Errors_ErrValue, 0, (int)__FILE__, __LINE__ );
1827|  }
1828|  va_end( va );
1829|
1830|  Errors_printf_release( "%s", msg );
1831|
1832|  ret = Errors_log2_p;
1833|  if ( Errors_log2_p < Errors_log2 + sizeof(Errors_log2) - sizeof(msg) ) {
1834|
1835|    /* テストケースを出力する */
1836|    if ( Errors_log_testCase[0] != '\0' ) {
1837|      strcpy( Errors_log2_p, Errors_log_testCase );
1838|      Errors_log_testCase[0] = '\0';
1839|      Errors_log2_p = strchr( Errors_log2_p, '\0' );
1840|      *Errors_log2_p = '\r';  Errors_log2_p ++;
1841|      *Errors_log2_p = '\n';  Errors_log2_p ++;
1842|    }
1843|    /* エラーメッセージを出力する */
1844|    strcpy( Errors_log2_p, msg );
1845|    Errors_log2_p = strchr( Errors_log2_p, '\0' );
1846|    *Errors_log2_p = '\r';  Errors_log2_p ++;
1847|    *Errors_log2_p = '\n';  Errors_log2_p ++;
1848|  }
1849|
1850|  #ifdef  ERRORS_PRINTF_TO_FILE
1851|    #ifndef  USES_FILEX
1852|      #error  need FileX
1853|    #endif
1854|    #ifdef   FOR_WINCE
1855|      #error  not support
1856|    #endif
1857|  {
1858|    FILE*  f;
1859|    static int bFirst = true;
1860|
1861|    if ( Errors_bPrintFileFirst ) {
1862|      remove( "errlog4.txt" );  Errors_bPrintFileFirst = false;
1863|    }
1864|    f = FileX_open( "errlog4.txt", "ab+" );
1865|    fputs( msg, f );  fputc( '\r', f );  fputc( '\n', f );
1866|    fclose( f );
1867|  }
1868|  #endif
1869|
1870|  return  ret;
1871|}
1872|
1873|
1874| 
1875|/**************************************************************************
1876|  6-16. <<< [Errors_testCasePrintf] テストケース出力用 printf >>> 
1877|【補足】
1878|・テストケースを表示するために使用します。
1879|・すぐに変数 Errors_log に出力しますが、次の Errors_errPrintf で
1880|  最新の Errors_testcasePrintf で出力した内容を、変数 Errors_log2 にも
1881|  出力します。
1882|***************************************************************************/
1883|char*  Errors_testCasePrintf( const char* fmt, ... )
1884|{
1885|  char  msg[1024];
1886|  va_list  va;
1887|
1888|  va_start( va, fmt );
1889|  vsprintf( msg, fmt, va );
1890|  if ( strlen( msg ) > sizeof(msg) ) {
1891|    strcpy( msg + sizeof(msg) - 4, "..." );
1892|    bf( Errors_ErrValue, 0, (int)__FILE__, __LINE__ );
1893|  }
1894|  va_end( va );
1895|
1896|  Errors_printf_release( "%s", msg );
1897|  strcpy( Errors_log_testCase, msg );
1898|
1899|  return  Errors_log_testCase;
1900|}
1901|
1902|
1903| 
1904|/**************************************************************************
1905|  6-17. <<< [Errors_printSize] サイズ出力用 printf >>> 
1906|【引数】
1907|  ・char*  guide;  ガイド(何のサイズかの説明)
1908|  ・int  size;     サイズ(バイト)
1909|【補足】
1910|・KB, MB の出力もします。
1911|***************************************************************************/
1912|#ifndef  ERRORS_CUT_DEBUG_TOOL
1913|void  Errors_printSize( const char* guide, int size )
1914|{
1915|  #ifdef  FOR_32BIT
1916|   Errors_printf_release( "  %s = %d, 0x%X, %dKB, %fMB",
1917|    guide, size, size, size / 1024, (float)size / (1024*1024) );
1918|  #endif
1919|}
1920|#endif
1921|
1922| 
1923|/**************************************************************************
1924|  6-18. <<< [ERRORS_PRINTF_FLUSH] エラーメッセージのログを出力する >>> 
1925|【補足】
1926|・エラーでなくても、Errors_printf のログを出力したい場合は、
1927|  メイン関数の最後でこの関数を呼び出します。
1928|・リリース時は、無効になります。
1929|・この関数を呼び出すたびに前のページ番号が出力されてしまいます。(バグ)
1930|
1931|  6-19. <<< [errlog] エラーログファイル >>>
1932|・errlog.txt は、ERRORS_PRINTF_TO_FILE による出力です。
1933|・errlog1.txt は、Errors_log 領域の出力です。
1934|・errlog2.txt は、Errors_log2 領域の出力です。
1935|***************************************************************************/
1936|#if 0
1937|#ifndef  ERRORS_CUT_DEBUG_TOOL
1938|void  ERRORS_PRINTF_FLUSH()
1939|{
1940|  #ifndef FOR_NOFILE
1941|  {
1942|    FILE*  file = fopen( "errlog1.txt", "wb" );
1943|    if ( Errors_LogTop_iPage == 1 )
1944|      fwrite( Errors_log, 1, Errors_log_p - Errors_log, file );
1945|    else
1946|      fwrite( Errors_log, 1, sizeof(Errors_log), file );
1947|    fclose( file );
1948|
1949|    file = fopen( "errlog2.txt", "wb" );
1950|    fwrite( Errors_log2, 1, Errors_log2_p - Errors_log2, file );
1951|    fclose( file );
1952|  }
1953|  #endif
1954|}
1955|#endif
1956|#endif
1957|
1958|
1959| 
1960|/**************************************************************************
1961|  6-20. <<< [Errors_clearLog] エラーメッセージの記録をクリアする >>> 
1962|***************************************************************************/
1963|void  Errors_clearLog()
1964|{
1965|  int  i;
1966|
1967|  for ( i = 0; i < Errors_log_size; i++ )
1968|    Errors_log[i] = '\0';
1969|  Errors_log_p = Errors_log;
1970|  Errors_LogTop_iPage = 1;
1971|
1972|  for ( i = 0; i < sizeof(Errors_log2); i++ )
1973|    Errors_log2[i] = '\0';
1974|  Errors_log2_p = Errors_log2;
1975|
1976|  for ( i = 0; i < sizeof(Errors_log_testCase); i++ )
1977|    Errors_log_testCase[i] = '\0';
1978|}
1979|
1980|
1981| 
1982|/**************************************************************************
1983|  6-21. <<< [Errors_getDispCh] 表示可能な文字を返す >>> 
1984|***************************************************************************/
1985|int  Errors_getDispCh( int c )
1986|{
1987|  if ( c == '\0' )  return  '0';
1988|  else if ( c == '\r' )  return ' ';
1989|  else if ( c == '\n' )  return ' ';
1990|  else if ( c > 0x100 || c < 0x20 )  return '.';
1991|  else  return  c;
1992|}
1993| 
1994|/**************************************************************************
1995|  6-22. <<< [Errors_printToMemory] メモリ出力 >>> 
1996|【内部補足】
1997|・Errors_printLowLevel から呼ばれます。
1998|***************************************************************************/
1999|char*  Errors_printToMemory( const char* msg )
2000|{
2001|  char*  ret;
2002|
2003|  if ( Errors_log_p >= Errors_log + sizeof(Errors_log) - strlen(msg) - 23 ) {
2004|    memset( Errors_log_p, 0, Errors_log + sizeof(Errors_log) - Errors_log_p );
2005|    #ifdef FOR_32BIT
2006|      bf2( 0xBBBBFFFF, Errors_LogTop_iPage, (int)__FILE__,__LINE__);
2007|    #else
2008|      bf2( 0xBBFF, Errors_LogTop_iPage, (int)__FILE__,__LINE__);
2009|    #endif
2010|    Errors_LogTop_iPage ++;
2011|    Errors_log_p = Errors_log;
2012|    sprintf( Errors_log_p, "--- Page %d\r\n", Errors_LogTop_iPage );
2013|    Errors_log_p = strchr( Errors_log_p, '\0' );
2014|  }
2015|  ret = Errors_log_p;
2016|  strcpy( Errors_log_p, msg );
2017|  Errors_log_p = strchr( Errors_log_p, '\0' );
2018|  *Errors_log_p = '\r';  Errors_log_p ++;
2019|  *Errors_log_p = '\n';  Errors_log_p ++;
2020|  if ( Errors_LogTop_iPage == 1 )
2021|    *Errors_log_p = '\0';
2022|  else {
2023|    sprintf( Errors_log_p, "\r\n--- Page %d\r\n", Errors_LogTop_iPage - 1 );
2024|    *strchr( Errors_log_p, '\0' ) = ' ';
2025|  }
2026|
2027|  return  ret;
2028|}
2029| 
2030|/**************************************************************************
2031|  6-23. <<< [Errors_printToConsole] 標準出力 >>> 
2032|【内部補足】
2033|・Errors_printLowLevel から呼ばれます。
2034|***************************************************************************/
2035|#if ( defined(USES_STDLIBS) || defined(FOR_DOS32) ) && ! defined(UNDER_CE)
2036|void  Errors_printToConsole( const char* msg )
2037|{
2038|  puts( msg );
2039|}
2040|#endif
2041| 
2042|/**************************************************************************
2043|  6-24. <<< [Errors_printToWindows] ダイアログ出力 >>> 
2044|【内部補足】
2045|・Errors_printLowLevel から呼ばれます。
2046|***************************************************************************/
2047|#if defined(FOR_WIN32)
2048|void  Errors_printToWindows( const char* msg )
2049|{
2050|  if ( MessageBox( (HWND)Errors_parentWnd, msg,
2051|      "エラーメッセージ", MB_OKCANCEL | MB_ICONERROR )
2052|      == IDCANCEL ) {
2053|    Errors_bStrongExit = true;
2054|    Errors_exit(__FILE__,__LINE__);
2055|  }
2056|}
2057|#endif
2058| 
2059|/**************************************************************************
2060|  6-25. <<< [Errors_printToFile] ファイル出力 >>> 
2061|【内部補足】
2062|・Errors_printLowLevel から呼ばれます。
2063|・実行ファイルのあるパスに出力します。
2064|***************************************************************************/
2065|#ifdef  USES_FILEX
2066|#ifdef  USES_STRX
2067|#ifndef FOR_WINCE
2068|void  Errors_printToFile( const char* msg )
2069|{
2070|  FILE*  f;
2071|  char  path[_MAX_PATH];
2072|
2073|  if ( StrX_argv0 == NULL ) {
2074|    static bool  b = false;
2075|
2076|    if ( ! b  ) {
2077|      Errors_printLowLevel( "StrX_argv0 が初期化されていないため、"
2078|        "Errors_printToFile が実行できません。" );
2079|      b = true;
2080|    }
2081|    return;
2082|  }
2083|
2084|  StrX_getExeFullPath( path, Errors_fileName, sizeof(path) );
2085|  if ( Errors_bPrintFileFirst ) {
2086|    remove( path );
2087|    Errors_bPrintFileFirst = false;
2088|
2089|    #ifndef  ERRORS_CUT_DEBUG_TOOL
2090|    {
2091|      char  msg2[_MAX_PATH + 256];
2092|
2093|      sprintf( msg2, "Error Message put to %s", path );
2094|      #ifdef  ERRORS_ERR_PRINTF_TO_WINDOW
2095|        if ( Errors_poolStart == NULL )
2096|          Errors_printToWindows( msg2 );
2097|      #endif
2098|      #ifdef  ERRORS_ERR_PRINTF_TO_STDOUT
2099|        Errors_printToConsole( msg2 );
2100|      #endif
2101|      #ifdef  ERRORS_ERR_PRINTF_TO_STDERR
2102|        fprintf( stderr, "%s\r\n", msg2 );
2103|      #endif
2104|      #ifdef  ERRORS_ERR_PRINTF_TO_MEMORY
2105|        Errors_printToMemory( msg2 );
2106|      #endif
2107|    }
2108|    #endif
2109|  }
2110|  f = fopen( path, "ab+" );
2111|  if ( f == NULL ) {
2112|    Errors_printLowLevel( "エラーファイルが開けません。" );
2113|    Errors_printLowLevel( path );
2114|    return;
2115|  }
2116|  fputs( msg, f );  fputc( '\r', f );  fputc( '\n', f );
2117|  fclose( f );
2118|}
2119|#endif
2120|#endif
2121|#endif
2122| 
2123|/**************************************************************************
2124|  6-26. <<< [Errors_printToPB] Platform Builder デバッグ・メッセージ出力 >>> 
2125|【補足】
2126|・RETAILMSG を使用しています。
2127|・msg は、Shift Jis コードの文字列です。(Unicode ではありません)
2128|***************************************************************************/
2129|#ifdef  FOR_WINCE
2130|void  Errors_printToPB( const char* msg )
2131|{
2132|  wchar_t  s[4096];
2133|
2134|//  setlocale( LC_ALL, "Japanese" );
2135|//  mbstowcs( s, msg, sizeof(s) );
2136|
2137|  MultiByteToWideChar( CP_ACP, 0, msg, -1, s, sizeof(s) );
2138|  RETAILMSG(1, (TEXT("%s\r\n"), s ));
2139|}
2140|#endif
2141| 
2142|/**************************************************************************
2143|  6-27. <<< [Errors_printLowLevel] 低レベル出力 >>> 
2144|【補足】
2145|・エラー出力システムが初期化できないときに使用します。
2146|・確実にプログラマに伝える方法を環境に応じて変えます。
2147|***************************************************************************/
2148|void  Errors_printLowLevel( const char* msg )
2149|{
2150|  #if defined(FOR_DOS32)
2151|    Errors_printToConsole( msg );
2152|  #elif  defined(FOR_WIN32)
2153|    Errors_printToWindows( msg );
2154|  #else
2155|    Errors_printToMemory( msg );
2156|  #endif
2157|}
2158|
2159| 
2160|/***************************************************************************
2161|  6-28. <<< [bf, _bf, bf2] ブレークポイントが実際に止まる場所 >>> 
2162|【引数】
2163|  ・int  返り値;    Errors_nextBreakCount に設定する値
2164|  (その他は Errors_break_imp 関数を参照)
2165|【補足】
2166|・アセンブラ・デバッガでは、_bf にブレークポイントを付けておきます。
2167|・bf2 は、Errors_printf, Errors_printf_release のバッファ(Error_log)がいっぱいに
2168|  なったときだけ呼ばれます。
2169|・アセンブラデバッガでは、ブレーク中に r6 に値を入れると、その回数だけ
2170|  次のブレークを無視します。→Errors_nextBreakCount 変数
2171|****************************************************************************/
2172|int  bf( int r6, int r7, int r8, int r9 )
2173|{
2174|  /* ブレークする */
2175|  #ifdef FOR_DOS32
2176|    getch();
2177|  #endif
2178|  #ifdef FOR_DOS16
2179|    getch();
2180|  #endif
2181|
2182|  #ifdef FOR_GHS
2183|    if ( !( r6 & 0xF0000000 ) )
2184|      return  r6;
2185|  #endif
2186|
2187|  r6,r7,r8,r9;  /* avoid warning */
2188|  return  1;
2189|}
2190|
2191|void  bf2( int r6, int r7, int r8, int r9 )  /* bf() と内容は同じ */
2192|{
2193|  /* ブレークする */
2194|  #ifdef FOR_DOS32
2195|    getch();
2196|  #endif
2197|  #ifdef FOR_DOS16
2198|    getch();
2199|  #endif
2200|
2201|  r6,r7,r8,r9;  /* avoid warning */
2202|}
2203|
2204|
2205| 
2206|/***************************************************************************
2207|  6-29. <<< [Errors_break_imp] ブレークポイント >>> 
2208|【引数】
2209|  ・int  r6;  0xBBBBBBBB=ブレーク、0xCCCCCCCC=表示なしブレーク
2210|  ・int  r7;  ヒント数値
2211|  ・int  r8;  ブレークしているファイル名のアドレス
2212|  ・int  r9;  ブレークしている行番号
2213|【補足】
2214|・デバッガでは、bf(アセンブラでは _bf)にブレークポイントを付けておきます。
2215|・Error_log をファイルに出力するようになっている場合、ブレークする直前で
2216|  Errors_printf_flush を実行します。
2217|****************************************************************************/
2218|void  Errors_break_imp( int r6, int r7, int r8, int r9 )
2219|{
2220|  if ( Errors_breakFlag && ( Errors_breakID == 0 || Errors_breakID == r7 ) ) {
2221|    if ( r6 != 0xCCCCCCCC ) {
2222|
2223|      /* ブレーク表示する */
2224|      Errors_printf_release( "break in %s(%d) : hint = %d(0x%X)", (char*)r8, r9, r7, r7 );
2225|      ERRORS_PRINTF_FLUSH();
2226|    }
2227|    Errors_breakCount ++;
2228|    ASSERT( Errors_nextBreakCount > 0 );
2229|    if ( Errors_nextBreakCount == 1 )
2230|      Errors_nextBreakCount = bf( r6, r7, r8, r9 );
2231|    else
2232|      Errors_nextBreakCount --;
2233|  }
2234|}
2235|
2236|
2237| 
2238|/***************************************************************************
2239|  6-30. <<< [Errors_breakFlag] ブレークフラグ >>> 
2240|【補足】
2241|・Errors_break コマンドによってブレークするかどうかのフラグです。
2242|・関数ツリーの深いところにあるブレークを有効にするか無効にするかを
2243|  コントロールすることができます。
2244|・プログラムでフラグを変更する場合は、Errors_setBreakFlag を使ってください。
2245|  デバッガで変更する場合は、Errors_breakFlag グローバル変数の値を
2246|  変更してください。
2247|****************************************************************************/
2248|bool  Errors_breakFlag = true;  /* ブレークフラグ */
2249|
2250|
2251| 
2252|/***************************************************************************
2253|  6-31. <<< ブレーク関連変数 >>> 
2254|  6-32. <<< [Errors_nextBreakCount] 次にブレークするブレーク位置(個数) >>>
2255|  6-33. <<< [Errors_breakCount] ブレーク・カウンタ >>>
2256|  6-34. <<< [Errors_breakID] ブレーク番号 >>>
2257|【補足】
2258|・Errors_break, Errors_break_release で、Errors_nextBreakCount 回分
2259|  次のブレークポイントで止まるようにします。その間、bf 関数の呼び出しをしません。
2260|・Errors_breakCount は、ブレークしたらカウントアップします。
2261|  ブレークポイント A から B までの間をスキップする場合は、
2262|  A でブレークしているときに、 Errors_nextBreakCountbf関数のr6)に
2263|  (B のカウント)-(A のカウント)を設定します。
2264|****************************************************************************/
2265|int  Errors_nextBreakCount = 1;
2266|int  Errors_breakCount = 0;
2267|int  Errors_breakID = 0;  /* Errors_setBreakID マクロを参照 */
2268|
2269| 
2270|/***************************************************************************
2271|  6-35. <<< [Errors_X, Errors_X2, Errors_X3] デバッグ用パラメータ >>> 
2272|【補足】
2273|・これらの変数は、再コンパイルしないでパラメータを変化させるときに
2274|  使います。
2275|・ERRORS_CUT_DEBUG_TOOL を #define すると使用できなくなります。
2276|****************************************************************************/
2277|#ifndef  ERRORS_CUT_DEBUG_TOOL
2278| int  Errors_X = 0;
2279| int  Errors_X2 = 1;
2280| int  Errors_X3 = 2;
2281| int  Errors_Line = 0;
2282|#endif
2283|
2284| 
2285|/*--------------------------------------------------------------------*/
2286|/* 7. <<<<◆ 関数コール履歴 >>>> */ 
2287|/*--------------------------------------------------------------------*/
2288|
2289| 
2290|#if  ! defined(ERRORS_CUT_DEBUG_TOOL) && defined(ERRORS_USE_FUNCLOG) 
2291|
2292|bool  Errors_FuncLog_inited = false;
2293|Errors_FuncLog  Errors_FuncLog_globl;
2294|
2295| 
2296|/***************************************************************************
2297|  7-1. <<< [Errors_FuncLog_init] 関数コール履歴の初期化 >>> 
2298|****************************************************************************/
2299|void  Errors_FuncLog_init( Errors_FuncLog* m )
2300|{
2301|  Errors_FuncLog_inited = true;
2302|  m->funcs_n = 0;
2303|  m->bLongJumped = false;
2304|}
2305|
2306| 
2307|/***************************************************************************
2308|  7-2. <<< [Errors_FuncLog_print_imp] Errors_FuncLog_print の関数部分 >>> 
2309|****************************************************************************/
2310|void  Errors_FuncLog_print_imp( Errors_FuncLog* m )
2311|{
2312|  Errors_FuncLog_Elem*  p;
2313|  Errors_FuncLog_Elem*  p_over;
2314|
2315|  if ( ! Errors_FuncLog_inited )
2316|    error2_0( Errors_Err_FuncLogNotInit, "Errors_FuncLog_init を呼び出していません" );
2317|
2318|  Errors_printf( "Func Call Stack ..." );
2319|
2320|  p_over = &m->funcs[m->funcs_n];
2321|  for ( p = &m->funcs[0];  p < p_over;  p++ ) {
2322|    Errors_printf( " %s()", p->name );
2323|  }
2324|}
2325|
2326|
2327| 
2328|/***************************************************************************
2329|  7-3. <<< [Errors_FuncLog_onLongJump] ロングジャンプしたときの処理 >>> 
2330|****************************************************************************/
2331|void  Errors_FuncLog_onLongJump( Errors_FuncLog* m )
2332|{
2333|  m->bLongJumped = true;
2334|}
2335|
2336|
2337| 
2338|/***************************************************************************
2339|  7-4. <<< [Errors_FuncLog_setStart] ERRORS_FUNC_START の関数部分 >>> 
2340|****************************************************************************/
2341|void  Errors_FuncLog_setStart( Errors_FuncLog* m, void* func, char* func_name )
2342|{
2343|  #ifdef  ERRORS_FUNCLOG_LED
2344|    LED7_outNum( ERRORS_FUNCLOG_LED, 2 );
2345|  #else
2346|    if ( ! Errors_FuncLog_inited )
2347|      error2_0( Errors_Err_FuncLogNotInit, "Errors_FuncLog_init を呼び出していません" );
2348|
2349|    #ifdef  ERRORS_FUNCLOG_PRINT_EVERY
2350|      Errors_printf( "%s() start", func_name );
2351|      if ( Errors_WATCH_adr != NULL )  WATCH();
2352|    #endif
2353|
2354|    if ( m->bLongJumped ) {
2355|      int  i;
2356|
2357|      m->bLongJumped = false;
2358|      for ( i = 0; i < Errors_FuncLog_size; i++ ) {
2359|        if ( m->funcs[i].adr == func ) {
2360|          m->funcs_n = i + 1;
2361|          return;
2362|        }
2363|      }
2364|      m->funcs_n = 0;
2365|    }
2366|
2367|    if ( m->funcs_n == Errors_FuncLog_size )  return;
2368|
2369|    m->funcs[m->funcs_n].adr = func;
2370|    m->funcs[m->funcs_n].name = func_name;
2371|    m->funcs_n++;
2372|  #endif
2373|}
2374|
2375|
2376| 
2377|/***************************************************************************
2378|  7-5. <<< [Errors_FuncLog_setEnd] ERRORS_FUNC_END の関数部分 >>> 
2379|****************************************************************************/
2380|void  Errors_FuncLog_setEnd( Errors_FuncLog* m, void* func, char* func_name )
2381|{
2382|  #ifdef  ERRORS_FUNCLOG_LED
2383|    LED7_outNum( ERRORS_FUNCLOG_LED, 4 );
2384|  #else
2385|    Errors_FuncLog_Elem*  p;
2386|    Errors_FuncLog_Elem*  p_first;
2387|
2388|    if ( ! Errors_FuncLog_inited )
2389|      error2_0( Errors_Err_FuncLogNotInit, "Errors_FuncLog_init を呼び出していません" );
2390|
2391|    #ifdef  ERRORS_FUNCLOG_PRINT_EVERY
2392|      Errors_printf( "%s() end", func_name );
2393|      if ( Errors_WATCH_adr != NULL )  WATCH();
2394|    #endif
2395|
2396|    p_first = &m->funcs[0];
2397|    for ( p = &m->funcs[m->funcs_n - 1];  p >= p_first;  p-- ) {
2398|      if ( p->adr == func )  { m->funcs_n = p - p_first;  return; }
2399|    }
2400|    Errors_printf( "Not find in FuncLog! Not match START/END or longjumped" );
2401|  #endif
2402|}
2403|
2404|
2405| 
2406|#endif  /* ERRORS_CUT_DEBUG_TOOL, ERRORS_USE_FUNCLOG */ 
2407| 
2408|