STDPLUS.C

[目次 | 関数 | マクロ]

目次

関数一覧

マクロ一覧


   1|/*************************************************************************
   2|*  1. <<< 標準ライブラリ拡張 (StdPlus) >>> 
   3|**************************************************************************/
   4|
   5|#include "mixer_precomp.h"  /* Auto precompiled header, Look at mixer-... folder */
   6|
   7|#define  STDLIBS_INCLUDE_STRING_H
   8|#define  STDLIBS_INCLUDE_STDARG_H
   9|#ifdef  USES_MXP_AUTOINC
  10| #include "stdplus.ah"  /* Auto include header, Look at mixer-... folder */
  11|#endif
  12|
  13|#ifndef  STDPLUS_NOT_ERRNO
  14|  #include  <errno.h>
  15|#endif
  16|
  17| 
  18|/*-----------------------------------------------------------------------*/
  19|/*  2. <<< ◆(StdPlus) 標準ライブラリ拡張 >>> */ 
  20|/*-----------------------------------------------------------------------*/
  21|
  22|int  StdPlus_mallocCount = 0;
  23|
  24| 
  25|/*************************************************************************
  26|*  3. <<< [StdPlus_printErrno] errno 変数の値をエラー表示する >>> 
  27|**************************************************************************/
  28|#if  !defined(STDPLUS_NOT_ERRNO) && ( defined(STDPLUS_USES_STDLIB) || defined(USES_FILEX) )
  29|void  StdPlus_printErrno()
  30|{
  31|  char*  s = "Unknown Error";
  32|
  33|  switch ( errno ) {
  34|    case  ECHILD:  s = "ECHILD   子プロセスが存在しない";  break;
  35|    case  EAGAIN:  s = "EAGAIN   これ以上プロセスを生成できない。";  break;
  36|    case  E2BIG:   s = "E2BIG   引数リストが長すぎる";  break;
  37|    case  EACCES:  s = "EACCES   アクセスが拒否された。";  break;
  38|    case  EBADF:   s = "EBADF   不正なファイル番号。";  break;
  39|    case  EDEADLOCK:  s = "EDEADLOCK   リソースのデッドロックが発生する可能性がある。";  break;
  40|    case  EDOM:    s = "EDOM   数値演算関数の引数が関数のドメイン外の値である。";  break;
  41|    case  EEXIST:  s = "EXIST   ファイルが存在する。";  break;
  42|    case  EINVAL:  s = "EINVAL   不正な引数。";  break;
  43|    case  EMFILE:  s = "EMFILE   開いているファイルが多すぎる。";  break;
  44|    case  ENOENT:  s = "ENOENT   ファイルまたはディレクトリがない。";  break;
  45|    case  ENOEXEC: s = "ENOEXEC   実行ファイルのエラー。";  break;
  46|    case  ENOMEM:  s = "ENOMEM   メモリ不足。";  break;
  47|    case  ENOSPC:  s = "ENOSPC   デバイスの空き領域不足。";  break;
  48|    case  ERANGE:  s = "ERANGE   結果が大きすぎる。";  break;
  49|    case  EXDEV:   s = "EXDEV   デバイス間リンク。";  break;
  50|  }
  51|
  52|  Errors_errPrintf( "errno = %d : %s", errno, s );
  53|}
  54|#endif
  55|
  56| 
  57|/***********************************************************************
  58|*  4. <<< [StdPlus_malloc] 拡張 malloc >>> 
  59|*  5. <<< [StdPlus_malloc_imp] >>>
  60|*【補足】
  61|*・メモリ領域を確保できなかった場合、エラーになります。
  62|*・StdPlus_free と呼出し回数をチェックすることができるようになります。
  63|* (StdPlus_chkFree 関数)
  64|*・StdPlus_malloc StdPlus_free はなるべく直接呼び出さないようにし、
  65|*  STDPLUS_USES_STDNAME を #define して、malloc StdPlus_malloc に
  66|*  書きかえるようにします。さもなければ、StdPlus_malloc 標準ライブラリの
  67|*  free を呼び出すようなことが起きる可能性が出てしまい、呼び出し回数の
  68|*  チェックがおかしくなることがあります。
  69|*・例外処理により確実に free するには次のようにします。
  70|*    Type*  p = NULL;   // NULL で初期化しておく
  71|*    try {
  72|*      p = malloc( 20 );  // try の中で StdPlus_malloc を呼び出す
  73|*       :
  74|*    }
  75|*    finally {    // finally または catch の中で StdPlus_free を呼び出す。
  76|*      free( p );    // StdPlus_free 内部で、NULL ならフリーしない
  77|*    } end_finally;
  78|************************************************************************/
  79|#ifdef  STDPLUS_USES_STDLIB
  80|
  81|int  StdPlus_chkAdr = 0x00000000;
  82|
  83|#ifndef  STDPLUS_PRINT_NOT_FREE
  84|  void*  StdPlus_malloc( int size )
  85|#else
  86|  void*  StdPlus_malloc_imp( int size, char* file, int line )
  87|#endif
  88|{
  89|  #ifdef  STDPLUS_USES_STDNAME
  90|    #undef  malloc
  91|  #endif
  92|
  93|  void*   p = malloc( size );
  94|
  95|  #ifdef  STDPLUS_PRINT_NOT_FREE
  96|    StdPlus_FreeChk_setMalloc( StdPlus_FreeChk_getGlobl(), p, file, line );
  97|  #endif
  98|
  99|  if ( p == NULL )
 100|    error2_0( StdPlus_Err_MallocFailure, "malloc できません" );
 101|  else
 102|    StdPlus_mallocCount ++;
 103|
 104|  /* デバッグ用、malloc した位置を知るため */
 105|  /* 次の free & malloc で同じアドレスを返すことがあるので注意 */
 106|  #ifndef  NDEBUG
 107|    if (  (int)p == StdPlus_chkAdr ) {  /* ここに開放されていないアドレスを記述する(1) */
 108|      Errors_printf( "malloc ( %p );", p );  /* ここにブレークポイントを張る */
 109|      //COUNT(0)
 110|      //  Errors_break(1);
 111|    }
 112|  #endif
 113|
 114|  return  p;
 115|
 116|  #ifdef  STDPLUS_USES_STDNAME
 117|    #define  malloc  StdPlus_malloc
 118|  #endif
 119|}
 120|#endif
 121|
 122| 
 123|/***********************************************************************
 124|*  6. <<< [StdPlus_free] 拡張 free >>> 
 125|*  7. <<< [StdPlus_free_imp] >>>
 126|*【補足】
 127|*・引数に NULL を指定した場合、何もしません。
 128|*・StdPlus_malloc と呼出し回数をチェックすることができるようになります。
 129|* (StdPlus_chkFree 関数)
 130|*・STDPLUS_PRINT_NOT_FREE を #define すると、free していないアドレスを
 131|*  表示できます。(Errors_chkDefault で)
 132|*・STDPLUS_USES_STDNAME を #define すると、free StdPlus_free に
 133|*  書きかえるようになります。
 134|************************************************************************/
 135|#ifdef  STDPLUS_USES_STDLIB
 136|
 137|#ifndef  STDPLUS_PRINT_NOT_FREE
 138|  void  StdPlus_free( void* p )
 139|#else
 140|  void  StdPlus_free_imp( void* p, char* file, int line )
 141|#endif
 142|{
 143|  #ifdef  STDPLUS_USES_STDNAME
 144|    #undef  free
 145|  #endif
 146|
 147|  #ifdef  STDPLUS_PRINT_NOT_FREE
 148|    StdPlus_FreeChk_setFree( StdPlus_FreeChk_getGlobl(), p, file, line );
 149|  #endif
 150|
 151|  if ( p != NULL ) {
 152|
 153|    /* デバッグ用、free した位置を知るため */
 154|    /* 次の free & malloc で同じアドレスを返すことがあるので注意 */
 155|    #ifndef  NDEBUG
 156|      if ( (int)p == StdPlus_chkAdr )  /* ここに開放されていないアドレスを記述する(2) */
 157|        Errors_printf( "free ( %p );", p );  /* ここにブレークポイントを張る */
 158|    #endif
 159|
 160|    free( p );
 161|    StdPlus_mallocCount --;
 162|  }
 163|
 164|  #ifdef  STDPLUS_USES_STDNAME
 165|    #define  free  StdPlus_free
 166|  #endif
 167|}
 168|#endif
 169|
 170| 
 171|/***********************************************************************
 172|*  8. <<< [StdPlus_chkMalloc] malloc したアドレスをチェックする >>> 
 173|*【引数】
 174|*  ・void* p1 ...;     malloc したポインタの羅列(最後は StdPlus_End)
 175|*  ・int  返り値;      Errors_NoError StdPlus_Err_MallocFailure
 176|*【例】
 177|*  StdPlus_chkMalloc( ptr, ptr2, StdPlus_End );
 178|*【補足】
 179|*・例外処理と StdPlus_malloc を使用すれば、本関数を使わなくても
 180|*  同じことができます。
 181|*・第1引数以降は malloc したポインタを並べて、最後は StdPlus_End を
 182|*  指定します。
 183|*・指定したポインタの中に1つでも NULL があれば、エラーになります。
 184|*  その際、NULL 以外のポインタを free してからエラーハンドラを呼び出します。
 185|*  エラーハンドラから戻ったら StdPlus_Err_MallocFailure を返します。
 186|************************************************************************/
 187|#ifdef  STDPLUS_USES_STDLIB
 188|int  StdPlus_chkMalloc( void* p1, ... )
 189|{
 190|  va_list  va;
 191|  void*  p;
 192|  bool   err = false;
 193|
 194|  /* NULL が1つでもあるかどうか */
 195|  va_start( va, p1 );
 196|  for (;;) {
 197|    p = va_arg( va, void* );
 198|    if ( p == StdPlus_End )   break;
 199|    if ( p == NULL )  { err = true;  break; }
 200|  }
 201|  va_end( va );
 202|
 203|  /* NULL があれば、NULL 以外を全て free してエラー */
 204|  if ( err ) {
 205|    va_start( va, p1 );
 206|    for (;;) {
 207|      p = va_arg( va, void* );
 208|      if ( p == StdPlus_End )  break;
 209|      if ( p != NULL )  free( p );
 210|    }
 211|    va_end( va );
 212|
 213|    error2_0( StdPlus_Err_MallocFailure, "malloc できませんでした" );
 214|    return  StdPlus_Err_MallocFailure;
 215|  }
 216|  else {
 217|    return  Errors_NoError;
 218|  }
 219|}
 220|#endif
 221|
 222| 
 223|/***********************************************************************
 224|*  9. <<< [StdPlus_chkFree] free した回数をチェックする >>> 
 225|*【補足】
 226|*・ERRORS_FINISHCHK から呼び出されます。
 227|*・通常、プログラムの最後で呼び出します。
 228|*・StdPlus_malloc StdPlus_free の呼出し回数が異なるときは、
 229|*  エラーになります。
 230|************************************************************************/
 231|void  StdPlus_chkFree()
 232|{
 233|  if ( StdPlus_mallocCount != 0 ) {
 234|    #ifdef  STDPLUS_PRINT_NOT_FREE
 235|      StdPlus_FreeChk_printNotFree( StdPlus_FreeChk_getGlobl() );
 236|    #endif
 237|    Errors_printf_release( "malloc free の回数が合いません。(%+d)",
 238|      StdPlus_mallocCount );
 239|  }
 240|}
 241|
 242| 
 243|/**************************************************************************
 244|*  10. <<< [StdPlus_itoa] 数値を文字列に変換する >>> 
 245|*【引数】
 246|*  ・int    value;    数値
 247|*  ・char*  string;   文字列を格納する領域の先頭アドレス
 248|*  ・int    radix;    進数
 249|*  ・char*  返り値;   string と同じ
 250|*【補足】
 251|*・16進数などのアルファベット文字は大文字になります。
 252|*・標準ライブラリ_itoa は存在しません。
 253|***************************************************************************/
 254|char*  StdPlus_itoa( int value, char* string, int radix )
 255|{
 256|  char*  p = string;
 257|  char*  pp;
 258|  int    m;
 259|  int    bMinus;
 260|
 261|  ASSERT( 1 <= radix && radix <= 36);
 262|
 263|  bMinus = (value < 0 );
 264|  if ( bMinus )  value = -value;
 265|
 266|  /* 下の桁から数字を格納する */
 267|  if ( radix <= 10 ) {
 268|    do {
 269|      m = value % radix;
 270|      *p = m + '0';
 271|      value /= radix;
 272|      p++;
 273|    } while ( value != 0 );
 274|  }
 275|  else {
 276|    do {
 277|      m = value % radix;
 278|      *p = m + ( m < 10 ?  '0' : 'A'-10 );
 279|      value /= radix;
 280|      p++;
 281|    } while ( value != 0 );
 282|  }
 283|  if ( bMinus ) {
 284|    *p = '-';  p++;
 285|  }
 286|  *p = '\0';
 287|
 288|  /* 下の桁から上の桁を入れ替える */
 289|  pp = string;  p--;
 290|  while ( pp < p ) {
 291|    m = *pp;  *pp = *p;  *p = m;
 292|    pp++;  p--;
 293|  }
 294|
 295|  return  string;
 296|}
 297|
 298|
 299|
 300| 
 301|/**************************************************************************
 302|*  11. <<< [StdPlus_utoa] 数値を文字列に変換する >>> 
 303|*【引数】
 304|*  ・unsigned int   value;    数値
 305|*  ・char*          string;   文字列を格納する領域の先頭アドレス
 306|*  ・int            radix;    進数
 307|*  ・char*          返り値;   string と同じ
 308|*【補足】
 309|*・16進数などのアルファベット文字は大文字になります。
 310|*・標準ライブラリ_utoa は存在しません。
 311|***************************************************************************/
 312|char*  StdPlus_utoa( unsigned value, char* string, int radix )
 313|{
 314|  char*  p = string;
 315|  char*  pp;
 316|  int    m;
 317|
 318|  ASSERT( 1 <= radix && radix <= 36);
 319|
 320|  /* 下の桁から数字を格納する */
 321|  if ( radix <= 10 ) {
 322|    do {
 323|      m = value % radix;
 324|      *p = m + '0';
 325|      value /= radix;
 326|      p++;
 327|    } while ( value != 0 );
 328|  }
 329|  else {
 330|    do {
 331|      m = value % radix;
 332|      *p = m + ( m < 10 ?  '0' : 'A'-10 );
 333|      value /= radix;
 334|      p++;
 335|    } while ( value != 0 );
 336|  }
 337|  *p = '\0';
 338|
 339|  /* 下の桁から上の桁を入れ替える */
 340|  pp = string;  p--;
 341|  while ( pp < p ) {
 342|    m = *pp;  *pp = *p;  *p = m;
 343|    pp++;  p--;
 344|  }
 345|
 346|  return  string;
 347|}
 348|
 349|
 350|
 351| 
 352|/**************************************************************************
 353|*  12. <<< [StdPlus_xtoi] 16進数文字列を数値に変換する >>> 
 354|*【引数】
 355|*  ・char*  hex;   16進数文字列
 356|*  ・int  返り値;  数値
 357|***************************************************************************/
 358|int  StdPlus_xtoi( char* hex )
 359|{
 360|  char*  s = hex;
 361|  int    c;
 362|  int    num = 0;
 363|
 364|  while ( *s != '\0' ) {
 365|    c = *s;
 366|    if ( c >= '0' && c < '9' )       num = num * 16 + (c - '0');
 367|    else if ( c >= 'A' && c < 'F' )  num = num * 16 + (c - 'A' + 10);
 368|    else if ( c >= 'a' && c < 'f' )  num = num * 16 + (c - 'a' + 10);
 369|    else  return  num;
 370|    s++;
 371|  }
 372|  return  num;
 373|}
 374|
 375|
 376| 
 377|/***********************************************************************
 378|*  13. <<< [StdPlus_inputS] 文字列の初期値の入力 >>> 
 379|*【引数】
 380|*  ・char*  msg;     プロンプト・メッセージ
 381|*  ・char*  out;     入力結果(出力)
 382|*  ・int  out_size;  out のサイズ
 383|*  ・char*  def;     デフォルト値
 384|*【補足】
 385|*・sdvex を使用しています。
 386|*・BS キーで入力しなおします。
 387|*・リターンキーのみで、デフォルト値が入力結果に格納されます。
 388|************************************************************************/
 389|#ifdef  USES_SDVEX
 390|void  StdPlus_inputS( const char* msg, char* out, int out_size, const char* def )
 391|{
 392|  int   i = 0;
 393|  int   c;
 394|  printf( "%s", msg );
 395|
 396|  for (;;) {
 397|    c = inkey();
 398|    if ( c == 0 )  continue;
 399|    else if ( c == 13 )  break;
 400|    #ifdef  USES_ERRORS
 401|    else if ( c == 0x1B )
 402|      error2_0( 0, "ユーザ・ブレイク" );
 403|    #endif
 404|    else if ( c == 8 ) {
 405|      printf( "\n%s", msg );
 406|      i = 0;
 407|    }
 408|    else {
 409|      if ( i < out_size - 1 ) {
 410|        printf( "%c", c );
 411|        out[i] = c;
 412|        i++;
 413|      }
 414|    }
 415|  }
 416|
 417|  /* 値を設定する */
 418|  if ( i == 0 ) {
 419|    strcpy( out, def );
 420|  }
 421|  else {
 422|    out[i] = '\0';
 423|  }
 424|  printf( "\n" );
 425|}
 426|#endif
 427|
 428|
 429| 
 430|/***********************************************************************
 431|*  14. <<< [StdPlus_inputX] 16進数の初期値の入力 >>> 
 432|************************************************************************/
 433|#ifdef  USES_SDVEX
 434|int  StdPlus_inputX( const char* msg, int def )
 435|{
 436|  enum { buf_size = 9 };
 437|  char  buf[buf_size];
 438|
 439|  StdPlus_inputS( msg, buf, buf_size, "" );
 440|
 441|  if ( buf[0] == '\0' )  return  def;
 442|  else  return  _xtoi( buf );
 443|}
 444|#endif
 445|
 446|
 447| 
 448|/*-----------------------------------------------------------------------*/
 449|/*  15. <<< ◆(StdPlus_FreeChk) free のし忘れを追跡するツール >>> */ 
 450|/*-----------------------------------------------------------------------*/
 451|
 452|#ifndef  ERRORS_CUT_DEBUT_TOOL
 453|#ifdef  STDPLUS_PRINT_NOT_FREE
 454|
 455|bool  StdPlus_FreeChk_inited = false;
 456|StdPlus_FreeChk   StdPlus_FreeChk_globl;
 457| 
 458|/***********************************************************************
 459|*  16. <<< [StdPlus_FreeChk_init] 初期化する >>> 
 460|*【補足】
 461|*・→StdPlus_FreeChk クラスの補足
 462|************************************************************************/
 463|void  StdPlus_FreeChk_init( StdPlus_FreeChk* m )
 464|{
 465|  StdPlus_FreeChkE*  p;
 466|  StdPlus_FreeChkE*  p_over = m->rec + StdPlus_FreeChk_Depth;
 467|
 468|  StdPlus_FreeChk_inited = true;
 469|
 470|  Errors_printf_release( "free し忘れの追跡ツールを起動します。" );
 471|
 472|  m->count = 0;
 473|  for ( p = m->rec; p < p_over; p++ ) {
 474|    p->adr = NULL;
 475|  }
 476|}
 477|
 478|
 479| 
 480|/***********************************************************************
 481|*  17. <<< [StdPlus_FreeChk_setMalloc] malloc に関する記録をする >>> 
 482|*【内部補足】
 483|*・StdPlus_malloc の内部で呼び出されます。
 484|************************************************************************/
 485|int  StdPlus_FreeChk_breakID = 2430;
 486|
 487|static  void  StdPlus_breakFunc()  {BK}   /* ここにブレークポイントを張ってください */
 488|
 489|
 490|void  StdPlus_FreeChk_setMalloc( StdPlus_FreeChk* m, void* adr, char* file, int line )
 491|{
 492|  StdPlus_FreeChkE*  p;
 493|  StdPlus_FreeChkE*  p_over;
 494|  m->count ++;
 495|  if ( StdPlus_FreeChk_breakID == m->count )  StdPlus_breakFunc();
 496|
 497|  if ( ! StdPlus_FreeChk_inited ) {
 498|    StdPlus_FreeChk_init( &StdPlus_FreeChk_globl );
 499|    //    Errors_printf( "StdPlus_FreeChk_init を呼び出してください" );
 500|    //    error();
 501|  }
 502|  p_over = m->rec + StdPlus_FreeChk_Depth;
 503|
 504|  for ( p = m->rec; p < p_over; p++ ) {
 505|    if ( p->adr == NULL ) {
 506|      #if  ERRORS_DEBUG_FALSE
 507|        Errors_printf( "malloc (%p) in %s(%d)", adr, file, line );
 508|      #endif
 509|      p->id = m->count;  p->adr = adr;  p->file = file;  p->line = line;
 510|      return;
 511|    }
 512|  }
 513|  error2_0( StdPlus_Err_CannotContinueCheck,
 514|    "StdPlus_FreeChk_Depth を大きくしてください。" );
 515|}
 516|
 517|
 518| 
 519|/***********************************************************************
 520|*  18. <<< [StdPlus_FreeChk_setFree] free に関する記録をする >>> 
 521|*【内部補足】
 522|*・StdPlus_free の内部で呼び出されます。
 523|************************************************************************/
 524|void  StdPlus_FreeChk_setFree( StdPlus_FreeChk* m, void* adr, char* file, int line )
 525|{
 526|  StdPlus_FreeChkE*  p;
 527|  StdPlus_FreeChkE*  p_over;
 528|
 529|  if ( ! StdPlus_FreeChk_inited ) {
 530|    StdPlus_FreeChk_init( &StdPlus_FreeChk_globl );
 531|    //Errors_printf( "StdPlus_FreeChk_init を呼び出してください" );
 532|    //error();
 533|  }
 534|  p_over = m->rec + StdPlus_FreeChk_Depth;
 535|
 536|  if ( adr == NULL ) {
 537|    error2_2( StdPlus_Err_NullFree, "NULL がフリーされました in %s(%d)", file, line );
 538|  }
 539|
 540|  for ( p = m->rec; p < p_over; p++ ) {
 541|    if ( p->adr == adr ) {
 542|      p->adr = NULL;
 543|      return;
 544|    }
 545|  }
 546|  error();
 547|}
 548| 
 549|/***********************************************************************
 550|*  19. <<< [StdPlus_FreeChk_printNotFree] free していないアドレスを表示する >>> 
 551|************************************************************************/
 552|void  StdPlus_FreeChk_printNotFree( StdPlus_FreeChk* m )
 553|{
 554|  StdPlus_FreeChkE*  p;
 555|  StdPlus_FreeChkE*  p_over = m->rec + StdPlus_FreeChk_Depth;
 556|  int  count = 0;
 557|
 558|  if ( ! StdPlus_FreeChk_inited ) {
 559|    Errors_printf( "StdPlus_FreeChk_init を呼び出してください" );
 560|    error();
 561|  }
 562|
 563|  Errors_printf( "StdPlus_FreeChk result: Not free adress is ..." );
 564|  for ( p = m->rec; p < p_over; p++ ) {
 565|    if ( p->adr != NULL ) {
 566|      Errors_printf( "id = %d, adr = %p in %s(%d)", p->id, p->adr, p->file, p->line );
 567|      count++;
 568|      if ( count == 100 ) {
 569|        Errors_printf( "100件を超えたので続きの表示を中止します。" );
 570|        break;
 571|      }
 572|    }
 573|  }
 574|  Errors_printf( "StdPlus_FreeChk Done." );
 575|}
 576| 
 577|#endif 
 578|#endif
 579| 
 580|