Filex.c

[目次 | 関数 | マクロ]

目次

関数一覧

マクロ一覧


   1|/**************************************************************************
   2|  1. <<< ファイルの拡張 (FileX) >>> 
   3|【補足】
   4|・標準ライブラリに無い特殊なファイル処理です。
   5|・ファイルパスに関する処理は、StrX コンポーネントを参照してください。
   6|・FILE 構造体だけでなく DOS ファイルハンドルも扱います。
   7|***************************************************************************/
   8|
   9|#include "mixer_precomp.h"  /* Auto precompiled header, Look at mixer-... folder */
  10|// #pragma hdrstop
  11|
  12|#ifdef  UNDER_CE  /* FOR_WINCE */
  13| #error  not support
  14|#endif
  15|
  16|#if ( defined(_WIN32) || defined(FOR_DOS32) ) && !defined(__BORLANDC__)
  17| //#include  <windows.h>
  18|#endif
  19|#include  <ctype.h>
  20|#define  STDLIBS_INCLUDE_STRING_H
  21|#define  STDLIBS_INCLUDE_STDLIB_H
  22|#ifdef  USES_MXP_AUTOINC
  23| #include "filex.ah"  /* Auto include header, Look at mixer-... folder */
  24|#endif
  25|
  26|#include  <io.h>
  27|#include  <direct.h>
  28|#include  <sys\types.h>
  29|#include  <sys\stat.h>
  30|#ifdef  USES_TIMEDATE
  31| #include  <sys\utime.h>
  32|#endif
  33|
  34|static char  FileX_buf[1024];
  35|bool  FileX_bCopyFailed = false;
  36|
  37|
  38| 
  39|/***************************************************************************
  40|  2. <<< [FileX_FNames_path] ファイル名バッファ >>> 
  41|【補足】
  42|・FileX_open したファイル名の記録です。
  43|・過去 FileX_FNames_m 個のファイルの FILE* 型アドレスとファイル名を記録します。
  44|***************************************************************************/
  45|#ifndef  NDEBUG
  46|  enum { FileX_FNames_m = 30 };
  47|  int    FileX_FNames_i = 0;     /* 次に格納する番号(ローテーションします)*/
  48|  FILE*  FileX_FNames_file[FileX_FNames_m];
  49|  char   FileX_FNames_path[FileX_FNames_m][_MAX_PATH];
  50|#endif
  51|
  52| 
  53|/***************************************************************************
  54|  3. <<< [FileX_getOpenedFName] 開いたファイル名を返す >>> 
  55|【引数】
  56|  ・FILE*  fp;    ファイルポインタ
  57|【補足】
  58|・FileX_open したファイル名のみ記録してあります。
  59|***************************************************************************/
  60|char*  FileX_getOpenedFName( FILE* fp )
  61|{
  62|  #ifndef  NDEBUG
  63|    int  i;
  64|
  65|    for ( i = FileX_FNames_i - 1; i != FileX_FNames_i; i-- ) {
  66|      if ( i < 0 ) {
  67|        i = FileX_FNames_m - 1;
  68|        if ( i == FileX_FNames_i )
  69|          break;
  70|      }
  71|      if ( fp == FileX_FNames_file[i] )
  72|        return  FileX_FNames_path[i];
  73|    }
  74|    if ( fp == FileX_FNames_file[i] )
  75|      return  FileX_FNames_path[i];
  76|
  77|    return  "(Not Opened or Deleted from Record)";
  78|  #else
  79|    return  "(FileName not Recorded)";
  80|  #endif
  81|}
  82|
  83|
  84| 
  85|/***************************************************************************
  86|  4. <<< [FileX_open] FILE* 型のファイルを開く >>> 
  87|【補足】
  88|・例外付きの fopen 関数です。
  89|***************************************************************************/
  90|#ifdef  USES_STRX
  91|FILE*  FileX_open( const char* path, const char* mode )
  92|{
  93|  FILE*  file;
  94|
  95|  ASSERT( path != NULL );
  96|  ASSERT( *path != 0 );
  97|  if ( strcmp( path, "\\\"" ) == 0 )
  98|    ((char*)(path))[1] = ' ';
  99|  file = fopen( path, mode );
 100|  if ( file == NULL ) {
 101|    char  path2[_MAX_PATH];
 102|
 103|    if ( strchr( mode, 'w' ) != NULL ) {
 104|      StrX_cpyFolder( path2, path );
 105|      if ( path2[0] != '\0' && ! FileX_isDir( path2 ) )
 106|        error2_1( FileX_Err_CannotWriteOpen,
 107|          "ファイルを格納するフォルダが無いので、ファイル \"%s\" が書きこめません", path );
 108|      else
 109|        error2_1( FileX_Err_CannotWriteOpen,
 110|          "ファイル \"%s\" が書きこめません(読み込み専用属性が付いているか、"
 111|          "フォルダです)", path );
 112|    }
 113|    else {
 114|      _getcwd( path2, sizeof(path2) );
 115|      error2_2( FileX_Err_CannotReadOpen,
 116|        "ファイル \"%s\" が見つかりません\n"
 117|        "カレント=%s", path, path2 );
 118|    }
 119|  }
 120|
 121|  #ifndef  NDEBUG
 122|    FileX_FNames_file[FileX_FNames_i] = file;
 123|    strcpy( FileX_FNames_path[FileX_FNames_i], path );
 124|    FileX_FNames_i ++;
 125|    if ( FileX_FNames_i == FileX_FNames_m )  FileX_FNames_i = 0;
 126|  #endif
 127|
 128|  return  file;
 129|}
 130|#endif
 131|
 132| 
 133|/***************************************************************************
 134|  5. <<< [FileX_getCSV] CSV 形式の1項目を入力する >>> 
 135|【引数】
 136|  ・char*  data;       項目を格納する文字列バッファ
 137|  ・int  data_maxLen;  data に格納できる最大のサイズ(\0含まず)
 138|【補足】
 139|・次に読み込むファイルポインタを、読み込む項目の先頭に移動してから呼び出し
 140|  てください。
 141|・次に読み込むファイルポインタは、',' または '\n' または EOF に移ります。
 142|・次の項目を読み込む前に ',' または '\n' を読み飛ばしてください。
 143|【例】
 144|・例1: abc,"abc,d""ef",123 (\n) なら data=[abc], ファイルポインタ = ','
 145|・例2: "abc,d""ef",123 (\n)     なら data=[abc,d"ef], ファイルポインタ = ','
 146|・例3: 123 (\n)                 なら data=[123], ファイルポインタ = '\n'
 147|***************************************************************************/
 148|void  FileX_getCSV( FILE* file, char* data, int data_maxLen )
 149|{
 150|  int    c, c2;
 151|  char*  data_over = data + data_maxLen;
 152|
 153|  c = fgetc( file );
 154|
 155|  /* "" の間を読み込む場合 */
 156|  if ( c == '"' ) {
 157|    c = fgetc( file );
 158|    c2 = fgetc( file );
 159|    while ( (c != '"' || c2 =='"') && c != EOF ) {
 160|      if ( data < data_over - 1 )
 161|        *data++ = (char)c;
 162|      if ( c == '"' && c2 == '"' )  c = fgetc( file );
 163|      else  c = c2;
 164|      c2 = fgetc( file );
 165|    }
 166|  }
 167|  /* , まで読み込む場合 */
 168|  else {
 169|    while ( c != ','  && c!= '\n' && c!= EOF ) {
 170|      if ( data < data_over - 1 )
 171|        *data++ = (char)c;
 172|      c = fgetc( file );
 173|    }
 174|    ungetc( c, file );
 175|  }
 176|  *data = '\0';
 177|}
 178|
 179|
 180| 
 181|/***************************************************************************
 182|  6. <<< [FileX_skipCSV] CSV 形式の1項目をスキップする >>> 
 183|【補足】
 184|・次に読み込むファイルポインタは、',' または '\n' または EOF に移ります。
 185|・次の項目を読み込む前に ',' または '\n' を読み飛ばしてください。
 186|***************************************************************************/
 187|void  FileX_skipCSV( FILE* file )
 188|{
 189|  char  c;
 190|
 191|  FileX_getCSV( file, &c, 0 );
 192|}
 193|
 194|
 195| 
 196|/***************************************************************************
 197|  7. <<< [FileX_putCSV] CSV 形式の1項目を出力する >>> 
 198|【補足】
 199|・必要に応じて "" で囲んだり " 文字を "" にします。
 200|・','や'\n'を出力しないので、別に行ってください。
 201|***************************************************************************/
 202|void  FileX_putCSV( FILE* file, char* data )
 203|{
 204|  bool  kakomu;  /* "" で囲むか */
 205|
 206|  kakomu = ( strchr( data, ',' ) || strchr( data, '"' ) );
 207|
 208|  if ( kakomu )  fprintf( file, "\"" );
 209|
 210|  while ( *data != '\0' ) {
 211|    if ( *data == '"' )  fprintf( file, "\"\"" );
 212|    else                 fprintf( file, "%c", *data );
 213|    data++;
 214|  }
 215|
 216|  if ( kakomu )  fprintf( file, "\"" );
 217|}
 218|
 219|
 220| 
 221|/************************************************************************
 222|  8. <<< [FileX_isExist] ファイルの存在を確かめる >>> 
 223|【引数】
 224|  ・char* fname;  ファイルへのパス名
 225|  ・bool 返り値;  ファイル or フォルダの存在
 226|【補足】
 227|・相対パスによって指定する場合、現在実行中のフォルダからの相対パスに
 228|  なります。
 229|・指定したパスがフォルダに一致する場合も、true を返します。
 230|*************************************************************************/
 231|#ifdef  USES_STRX
 232|#ifdef  USES_EXCEPT3
 233|bool  FileX_isExist( const char* fname )
 234|{
 235|  if ( strstr( fname, ".." ) != NULL ) {
 236|    char  path[_MAX_PATH];
 237|
 238|    c_try {
 239|      StrX_getRunFullPath( path, fname, sizeof(path) );
 240|    }
 241|    c_catch ( Errors_Msg*, err ) {
 242|      if ( err->code == StrX_Err_NoMoreParentDir )
 243|        strcpy( path, ".." );
 244|    } c_end_catch;
 245|    if ( strstr( path, ".." ) != NULL )
 246|      return  false;
 247|  }
 248|  return  (_access( fname, 0 ) == 0);
 249|}
 250|#endif
 251|#endif
 252| 
 253|/************************************************************************
 254|  9. <<< [FileX_isDir] フォルダの存在を確かめる >>> 
 255|【引数】
 256|  ・const char* fname;  フォルダへのパス名
 257|  ・bool 返り値;        フォルダの存在
 258|【補足】
 259|・相対パスによって指定する場合、現在実行中のフォルダからの相対パスに
 260|  なります。
 261|・指定したパスがファイルに一致する場合、false を返します。
 262|*************************************************************************/
 263|#ifdef  USES_STRX
 264|bool  FileX_isDir( const char* path )
 265|{
 266|  struct _stat  stat;
 267|  char  path2[_MAX_PATH];
 268|
 269|  strcpy( path2, path );
 270|  StrX_cutLastOf2( path2, '/' );
 271|  StrX_cutLastOf2( path2, '\\' );
 272|  if ( path2[2]== '\0' && path2[1] == ':' && isalpha( path2[0] ) )
 273|    return  true;
 274|
 275|  if ( _stat( path2, &stat ) )  return  false;
 276|  return ( stat.st_mode & _S_IFDIR ) ? true : false;
 277|}
 278|#endif
 279|
 280|
 281| 
 282|/************************************************************************
 283|  10. <<< [FileX_getOneExistWild] ワイルドカードに一致するファイルパスを得る >>> 
 284|【引数】
 285|  ・char*  wild_path;   ワイルドカードを含んだファイルパス
 286|  ・char*  first_path;  一致したパス(一致したうちの1つ)(サイズは _MAX_PATH)
 287|  ・int  返り値;        一致したファイルの数
 288|*************************************************************************/
 289|int  FileX_getOneExistWild( const char* wild_path, char* first_path )
 290|{
 291|  long  handle;
 292|  int  n = 0;
 293|  struct _finddata_t  data;
 294|
 295|  handle = _findfirst( (char*)wild_path, &data );
 296|  if ( handle != -1 ) {
 297|
 298|    StrX_cpyFolder( first_path, wild_path );
 299|    StrX_addFName( first_path, data.name );
 300|    n ++;
 301|
 302|    while ( _findnext( handle, &data ) != -1 )
 303|      n++;
 304|
 305|    _findclose( handle );
 306|  }
 307|
 308|  return  n;
 309|}
 310|
 311| 
 312|/************************************************************************
 313|  11. <<< [FileX_getUpdate] ファイルの更新日時を取得する >>> 
 314|【引数】
 315|  ・time_t*  date;  更新日時を格納するアドレス
 316|【補足】
 317|・相対パスによって指定する場合、現在実行中のフォルダからの相対パスに
 318|  なります。
 319|・ファイルが存在しない場合、動作未定義です。
 320|・time_t 型は、ctime や difftime などの標準関数に使うことが出来ます。
 321|*************************************************************************/
 322|#ifdef  USES_STDPLUS
 323|void  FileX_getUpdate( const char* fName, time_t* date )
 324|{
 325|  int  r;
 326|  struct _stat  status;
 327|
 328|  r = _stat( fName, &status );
 329|  if ( r != 0 ) {
 330|    StdPlus_printErrno();
 331|    error();
 332|  }
 333|
 334|  *date = status.st_mtime;
 335|}
 336|#endif  /* USES_STDPLUS */
 337|
 338|
 339| 
 340|/************************************************************************
 341|  12. <<< [FileX_setUpdate] ファイルの更新日時を変更する >>> 
 342|【引数】
 343|  ・time_t*  date;  更新日時を格納するアドレス
 344|【補足】
 345|・相対パスによって指定する場合、現在実行中のフォルダからの相対パスに
 346|  なります。
 347|*************************************************************************/
 348|#if  defined(USES_STDPLUS) && defined(USES_TIMEDATE)
 349|void  FileX_setUpdate( const char* path, time_t* date )
 350|{
 351|  struct _utimbuf  tim;
 352|
 353|  time( &tim.actime );
 354|  tim.modtime = *date;
 355|  if ( _utime( path, &tim ) == -1 )
 356|    error();
 357|}
 358|#endif
 359|
 360|
 361| 
 362|/************************************************************************
 363|  13. <<< [FileX_getSize] ファイルサイズを返す >>> 
 364|【補足】
 365|・相対パスによって指定する場合、現在実行中のフォルダからの相対パスに
 366|  なります。
 367|・使用サイズを取得するには、FileX_FreeSpc_getUseFileSize 関数を使用して
 368|  ください。
 369|・ファイルが存在しない場合や無効なパスを指定したときは、0 を返します。
 370|*************************************************************************/
 371|int   FileX_getSize( const char* path )
 372|{
 373|  int  r;
 374|  struct _stat  status;
 375|
 376|  r = _stat( path, &status );
 377|  if ( r != 0 )  return  0;
 378|
 379|  return  status.st_size;
 380|}
 381| 
 382|/************************************************************************
 383|  14. <<< [FileX_getSftSum] シフトチェックサムの値を返す >>> 
 384|【引数】
 385|  ・int  maxFileSize;  調査する最大のファイルサイズ(-1=ファイル全部)
 386|【補足】
 387|・シフトチェックサムの値は、ファイルの先頭から1バイトごとに合計した値ですが、
 388|  ファイルアドレスを7で割った余りの分だけ左シフトしてから加算します。
 389|・maxFileSize を指定すると、先頭から指定のバイト数までの合計をします。
 390|・相対パスによって指定する場合、現在実行中のフォルダからの相対パスに
 391|  なります。
 392|*************************************************************************/
 393|int   FileX_getSftSum( const char* path, int maxFileSize )
 394|{
 395|  FILE*  f;
 396|  int  c;
 397|  int  sum = 0;
 398|  int  adr = 0;
 399|  int  adr_mod7 = 0;   /* ファイルアドレスを7で割った余り */
 400|
 401|  f = FileX_open( path, "rb" );
 402|  while ( ( c = fgetc( f ) ) != EOF && adr < maxFileSize ) {
 403|    sum += ( c << adr_mod7 );
 404|    adr ++;
 405|    adr_mod7 = ( adr_mod7 == 6 ? 0 : adr_mod7 + 1 );
 406|  }
 407|
 408|  fclose( f );
 409|
 410|  return  sum;
 411|}
 412| 
 413|/************************************************************************
 414|  15. <<< [FileX_getPathes] フォルダに入っているファイルパスを取得する >>> 
 415|【引数】
 416|  ・char*  folder;      フォルダパス(絶対パス)
 417|  ・StrX_Mem*  files;   ファイルパスの格納場所(初期化済みを指定)
 418|【補足】
 419|・絶対パスで格納します。
 420|・ファイルパスは、StrX_Mem_alloc で確保した領域に格納ます。
 421|*************************************************************************/
 422|#ifdef  USES_FILEFIND
 423|#ifdef  USES_STRX
 424|void  FileX_getPathes( const char* folder, StrX_Mem* files )
 425|{
 426|  FileFind  find;
 427|  char*  s;
 428|
 429|  FileFind_init( &find, folder );
 430|
 431|  while ( FileFind_next( &find ) == 0 ) {
 432|    if ( ! FileFind_isDir( &find ) ) {
 433|      s = StrX_Mem_alloc( files );
 434|      strcpy( s, folder );  s = strchr( s, '\0' );
 435|      *s = '\\';  s++;
 436|      strcpy( s, FileFind_getFName( &find ) );
 437|    }
 438|  }
 439|  FileFind_finish( &find );
 440|}
 441|#endif  /* USES_STRX */
 442|#endif  /* USES_FILEFIND */
 443|
 444|
 445| 
 446|/************************************************************************
 447|  16. <<< [FileX_isUpdate] ファイルが同一バージョンか判断する >>> 
 448|【機能】
 449|・ファイルの更新日時が秒単位なのを利用して、ファイルが同一バージョンか
 450|  どうか判断します。
 451|【引数】
 452|  ・const char* fName;  判断するファイル名
 453|  ・time_t* date;       入力は、比較対象となるバージョンの更新日付
 454|                        出力は、fName のファイルの更新日付
 455|  ・bool  返り値;       同一バージョンかどうか
 456|【補足】
 457|・もし、時計のずれや、頻繁な更新のために、偶然に同一時刻になった場合、
 458|  正しく判断できません。
 459|**************************************************************************/
 460|bool  FileX_isUpdate( const char* fName, time_t* date )
 461|{
 462|  bool  ret;
 463|  int  r;
 464|  struct _stat  status;
 465|
 466|  r = _stat( fName, &status );
 467|  ASSERT( r == 0 );
 468|
 469|  ret = (*date == status.st_mtime );
 470|  *date = status.st_mtime;
 471|  return  ret;
 472|}
 473|
 474|
 475| 
 476|/************************************************************************
 477|  17. <<< [FileX_cmpTime] ファイルの更新日時を比較する >>> 
 478|【引数】
 479|  ・int 返り値;  0=等しい、0より大(>) fNameA のファイルが新しい
 480|                           0より小(<) fNameB のファイルが新しい
 481|【補足】
 482|・相対パスによって指定する場合、現在実行中のフォルダからの相対パスに
 483|  なります。
 484|・ファイルの存在と更新日時に対する返り値の関係は次の通りです。
 485|   [fNameA] [更新日時] [fNameB] [返り値]
 486|     存在       ==       存在      0
 487|     存在       >        存在      1
 488|     存在       <        存在     -1
 489|     存在                なし      2
 490|     なし                存在     -2
 491|     なし                なし      0
 492|・新しいファイルを上書きコピーするものと同じアルゴリズムを使って、
 493|  新しいファイルを作る(コピーする)ことができます。
 494|・引数にファイル名を指定しない場合、TimeDate_cmpTime 関数を用います。
 495|*************************************************************************/
 496|#ifdef  USES_STDPLUS
 497|#ifdef  USES_EXCEPT3
 498|int  FileX_cmpTime( const char* fNameA, const char* fNameB )
 499|{
 500|  time_t  timeA, timeB;
 501|  double  diffTime;
 502|
 503|  // ファイルの存在しない場合、最も古いものとして比較する
 504|  if ( ! FileX_isExist( fNameA ) ) {
 505|    if ( ! FileX_isExist( fNameB ) )  return  0;
 506|    else  return  -2;
 507|  }
 508|  else if ( ! FileX_isExist( fNameB ) )  return  2;
 509|
 510|  // 両方のファイルの日付を比較する
 511|  FileX_getUpdate( fNameA, &timeA );
 512|  FileX_getUpdate( fNameB, &timeB );
 513|  diffTime = difftime( timeA, timeB );
 514|  if ( diffTime > 0 )  return  1;
 515|  else if ( diffTime < 0 )  return  -1;
 516|  else  return  0;
 517|}
 518|#endif
 519|#endif /* USES_STDPLUS */
 520|
 521|
 522| 
 523|/***********************************************************************
 524|  18. <<< [FileX_getTmpPath] テンポラリファイルのパスを作成する >>> 
 525|【引数】
 526|  ・char*  prefix;   ファイル名に付ける接頭辞
 527|  ・char*  path;     作成したパスを格納するアドレス(サイズは _MAX_PATH)
 528|【補足】
 529|・Windows の場合、通常 c:\Windows\Temp フォルダの中のファイルへのパスを
 530|  作成します。
 531|************************************************************************/
 532|void  FileX_getTmpPath( const char* prefix, char* path )
 533|{
 534|  static char*  defTmpDir = "\\";
 535|  char*  s;
 536|
 537|  s = _tempnam( defTmpDir, (char*)prefix );
 538|  strcpy( path, s );
 539|
 540|  #ifdef  STDPLUS_USES_STDNAME
 541|    #undef  free
 542|  #endif
 543|
 544|  free( s );
 545|
 546|  #ifdef  STDPLUS_USES_STDNAME
 547|    #define  free  StdPlus_free
 548|  #endif
 549|}
 550|
 551| 
 552|/***********************************************************************
 553|  19. <<< [FileX_getTmpPath2] テンポラリファイルのパスを作成する(フォルダ指定) >>> 
 554|【引数】
 555|  ・char*  prefix;   ファイル名に付ける接頭辞
 556|  ・char*  path;     作成したパスを格納するアドレス(サイズは _MAX_PATH)
 557|  ・char*  folder;   テンポラリファイルを作成するフォルダ(絶対パス)
 558|************************************************************************/
 559|#ifdef  USES_STRX
 560|#ifdef  USES_EXCEPT3
 561|void   FileX_getTmpPath2( const char* prefix, const char* folder, char* path )
 562|{
 563|  int  i = 1;
 564|  int  bDir = FileX_isDir( folder );
 565|
 566|  for (;;) {
 567|    if ( bDir ) {
 568|      if ( StrX_getLast( folder ) == '\\' )
 569|        sprintf( path, "%s%s%d", folder, prefix, i );
 570|      else
 571|        sprintf( path, "%s\\%s%d", folder, prefix, i );
 572|    }
 573|    else {
 574|      StrX_cpyFolder( path, folder );
 575|      sprintf( strchr( path, '\0' ), "\\%s%d", prefix, i );
 576|    }
 577|    if ( ! FileX_isExist( path ) )  return;
 578|    i++;
 579|  }
 580|}
 581|#endif
 582|#endif
 583| 
 584|/***********************************************************************
 585|  20. <<< [FileX_getTmpPath2] テンポラリファイルのパスを作成する(フォルダ指定) >>> 
 586|【引数】
 587|  ・char*  prefix;   ファイル名に付ける接頭辞
 588|  ・char*  path;     作成したパスを格納するアドレス(サイズは _MAX_PATH)
 589|  ・char*  folder;   テンポラリファイルを作成するフォルダ(絶対パス)
 590|************************************************************************/
 591|#if  defined(USES_WINX) && defined(USES_STRX) && defined(USES_EXCEPT3)
 592|void  FileX_getTmpPath3( const char* folder, const char* prefix, const char* ext, char* path )
 593|{
 594|  int   i = 1;
 595|  bool  b;
 596|
 597|  if ( folder == NULL || ! FileX_isDir( folder ) ) {
 598|    folder = WinX_getTempPath();
 599|  }
 600|
 601|  b = ( StrX_getLast( folder ) == '\\' );
 602|
 603|  for (;;) {
 604|    if ( b )
 605|      sprintf( path, "%s%s%d.%s", folder, prefix, i, ext );
 606|    else
 607|      sprintf( path, "%s\\%s%d.%s", folder, prefix, i, ext );
 608|
 609|    if ( ! FileX_isExist( path ) )  return;
 610|    i++;
 611|  }
 612|}
 613|#endif
 614| 
 615|/*************************************************************************
 616|  21. <<< [FileX_isDiff] 2つのファイルの内容が同一かどうか調べる >>> 
 617|【引数】
 618|  ・int  返り値;   0=同一、 1=異なる、-1=fname1 が開けない、
 619|                  -2=fname2 が開けない、-3=fname1,fname2 とも開けない
 620|【補足】
 621|・両方のファイルが存在して、内容が同一かどうかを判定するならば、
 622|  返り値は bool 値(0か0以外か)として判定することができます。
 623|**************************************************************************/
 624|int  FileX_isDiff( const char* fNameA, const char* fNameB )
 625|{
 626|  int  ret;
 627|  FILE  *file1, *file2;
 628|  int  size1, size2;
 629|  static char  buf1[256], buf2[256];
 630|
 631|  file1 = fopen( fNameA, "rb" );
 632|  file2 = fopen( fNameB, "rb" );
 633|
 634|  if ( file1 == NULL ) {
 635|    if ( file2 == NULL )  return  -3;
 636|    else {
 637|      fclose( file2 );
 638|      return -1;
 639|    }
 640|  }
 641|  if ( file2 == NULL ) {
 642|    fclose( file1 );
 643|    return -2;
 644|  }
 645|
 646|  ret = 1;
 647|  for (;;) {
 648|    size1 = fread( buf1, 1, 256, file1 );
 649|    size2 = fread( buf2, 1, 256, file2 );
 650|
 651|    if ( size1 != size2 )  break;
 652|    if ( memcmp( buf1, buf2, size1 ) != 0 )  break;
 653|
 654|    if ( size1 != 256 )  { ret = 0; break; }
 655|  }
 656|
 657|  fclose( file1 );
 658|  fclose( file2 );
 659|
 660|  return  ret;
 661|}
 662|
 663|
 664| 
 665|/*************************************************************************
 666|  22. <<< [FileX_copy] ファイルをコピーする >>> 
 667|【補足】
 668|・to_path は、フォルダ名だけでなく、ファイル名まで指定してください。
 669|**************************************************************************/
 670|#if  defined(USES_STDPLUS) && defined(USES_STRX)
 671|#if  defined(USES_BIGSTACK) && defined(USES_EXCEPT3) && defined(USES_TIMEDATE)
 672|#if  defined(FOR_WIN32) || defined(FOR_DOS32)
 673|void  FileX_copy( const char* to_path, const char* from_path )
 674|{
 675|  FileX_copy2( to_path, from_path, NULL, NULL );
 676|}
 677|#endif
 678|#endif
 679|#endif
 680|
 681| 
 682|/*************************************************************************
 683|  23. <<< [FileX_copy2] ファイルをコピーする(コールバック付き) >>> 
 684|【引数】
 685|  ・FileX_CopyBack  callback;  進捗状況表示のためのコールバック関数
 686|【補足】
 687|・to_path は、フォルダ名だけでなく、ファイル名まで指定してください。
 688|・fwrite を実行するたびに callback 関数を呼び出します。
 689|・書き込みに失敗した場合、エラーになり、それまでにコピーしたデータは削除されます。
 690|**************************************************************************/
 691|#if  defined(USES_STDPLUS) && defined(USES_STRX)
 692|#if  defined(USES_BIGSTACK) && defined(USES_EXCEPT3) && defined(USES_TIMEDATE)
 693|#if  defined(WIN32) || defined(FOR_DOS32)
 694|void  FileX_copy2( const char* to_path, const char* from_path,
 695|  FileX_CallBack callback, void* obj )
 696|{
 697|  FILE*  to_file;
 698|  FILE*  from_file;
 699|  size_t  size;
 700|  struct _utimbuf  tim;
 701|  time_t  date;
 702|  int     now = 0, all;
 703|  DWORD   attr;
 704|  BOOL    bSuccess;
 705|
 706|  if ( ! FileX_isExist( from_path ) ) {
 707|    error2_1( FileX_Err_NotFindCopySrc, "コピー元が見つかりません %s",
 708|      from_path );
 709|  }
 710|
 711|  /* ファイルの属性を取得する */
 712|  attr = GetFileAttributes( from_path );
 713|  if ( attr == 0xFFFFFFFF )  error();
 714|  FileX_getUpdate( from_path, &date );
 715|  all = FileX_getSize( from_path );
 716|
 717|  /* ファイルを開く */
 718|  FileX_mkdir2( to_path, true );
 719|  to_file = FileX_open( to_path, "wb" );
 720|  from_file = FileX_open( from_path, "rb" );
 721|
 722|  /* ファイルの内容をコピーする */
 723|  if ( callback != NULL )  callback( obj, now, all );
 724|  do {
 725|    size = fread( FileX_buf, 1, sizeof(FileX_buf), from_file );
 726|    if ( fwrite( FileX_buf, 1, size, to_file ) != size ) {
 727|      fclose( to_file );  fclose( from_file );
 728|      remove( to_path );
 729|      FileX_bCopyFailed = true;
 730|      error2_1( FileX_Err_CannotWrite, "%s の書きこみに失敗しました。",
 731|        to_path );
 732|    }
 733|    now += size;
 734|    if ( callback != NULL )  callback( obj, now, all );
 735|  } while ( size == sizeof(FileX_buf) );
 736|
 737|  /* ファイルを閉じる */
 738|  fclose( to_file );
 739|  fclose( from_file );
 740|
 741|  /* 更新日付やファイル属性を元のファイルと同じにする */
 742|  time( &tim.actime );
 743|  tim.modtime = date;
 744|  _utime( to_path, &tim );
 745|  bSuccess = SetFileAttributes( to_path, attr );
 746|  if ( ! bSuccess )  error();
 747|}
 748|#endif
 749|#endif
 750|#endif
 751|
 752| 
 753|/*************************************************************************
 754|  24. <<< [FileX_move] ファイルまたはフォルダを移動する >>> 
 755|【補足】
 756|・from_path にフォルダのパスを指定することも出来ます。
 757|・to_path は、格納するフォルダ名だけでなく、ファイル名(フォルダ名)まで
 758|  指定してください。
 759|・ドライブが異なる場合、コピーを実行するためパフォーマンスが落ちることがあります。
 760|・移動先にファイルがある場合は上書きします。
 761|・移動先にフォルダがある場合、フォルダに含まれるファイル名が一致するときのみ
 762|  ファイルを上書きします。
 763|・書き込みに一度でも失敗した場合、データ保護のためコピー元の削除を一切
 764|  行わなくなります。この状態から復元するには、FileX_bCopyFailed グローバル変数を
 765|  false にしてください。
 766|**************************************************************************/
 767|#ifdef  USES_STRX
 768|#ifdef  USES_STDPLUS
 769|#ifdef  USES_FILEFIND
 770|#ifdef  USES_NESTFIND
 771|#ifdef  USES_BIGSTACK
 772|#ifdef  USES_WINX
 773|void  FileX_move( const char* to_path, const char* from_path )
 774|{
 775|  if ( MoveFile( from_path, to_path ) == 0 ) {
 776|    if ( FileX_isDir( from_path ) ) {
 777|      FileX_copyFolder( to_path, from_path, true );
 778|      if ( ! FileX_bCopyFailed )
 779|        FileX_removeFolder( from_path );
 780|    }
 781|    else {
 782|      FileX_copy2( to_path, from_path, NULL, NULL );
 783|      if ( ! FileX_bCopyFailed ) {
 784|        if ( remove( from_path ) == -1 )
 785|          error2_1( FileX_Err_AccessDenied, "%s が削除できません", from_path );
 786|      }
 787|    }
 788|  }
 789|}
 790|#endif
 791|#endif
 792|#endif
 793|#endif
 794|#endif
 795|#endif
 796|
 797| 
 798|/*************************************************************************
 799|  25. <<< [FileX_copyPickup] ファイルの一部をコピーする >>> 
 800|【引数】
 801|  ・char*  to_path;    コピー先(絶対パス)
 802|  ・char*  from_path;  コピー元(絶対パス)
 803|  ・int  startPos;     開始ファイルアドレス
 804|  ・int  endPos;       終了ファイルアドレスの次(FILEX_TO_LAST, FILEX_TO_FULLも可)
 805|  ・int  返り値        コピーしたファイルのサイズ
 806|【補足】
 807|・to_path は、フォルダ名だけでなく、ファイル名まで指定してください。
 808|・endPos のアドレスの直前までコピーします。endPos のアドレスの内容はコピーしません。
 809|・endPos に FILEX_TO_LAST を指定すると最後までコピーします。
 810|  FILEX_TO_FULL を指定するとディスクの容量をチェックしてできる限りコピーします。
 811|**************************************************************************/
 812|#if  defined(USES_STDPLUS) && defined(USES_STRX)
 813|#if  defined(USES_BIGSTACK) && defined(USES_EXCEPT3) && defined(USES_TIMEDATE)
 814|#if  defined(WIN32) || defined(FOR_DOS32)
 815|int   FileX_copyPickup( const char* to_path, const char* from_path,
 816|  int startPos, int endPos )
 817|{
 818|  return  FileX_copyPickup2( to_path, from_path,
 819|     startPos, endPos, NULL, NULL );
 820|}
 821|#endif
 822|#endif
 823|#endif
 824|
 825| 
 826|/*************************************************************************
 827|  26. <<< [FileX_copyPickup2] ファイルの一部をコピーする >>> 
 828|【引数】
 829|  ・char*  to_path;    コピー先(絶対パス)
 830|  ・char*  from_path;  コピー元(絶対パス)
 831|  ・int  startPos;     開始ファイルアドレス
 832|  ・int  endPos;       終了ファイルアドレスの次(FILEX_TO_LAST, FILEX_TO_FULLも可)
 833|  ・int  返り値        コピーしたファイルのサイズ
 834|【補足】
 835|・to_path は、フォルダ名だけでなく、ファイル名まで指定してください。
 836|・endPos のアドレスの直前までコピーします。endPos のアドレスの内容はコピーしません。
 837|・endPos に FILEX_TO_LAST を指定すると最後までコピーします。
 838|  FILEX_TO_FULL を指定するとディスクの容量をチェックしてできる限りコピーします。
 839|**************************************************************************/
 840|#ifdef  WIN32
 841|#ifdef  USES_STRX
 842|#ifdef  USES_EXCEPT3
 843|#ifdef  USES_BIGSTACK
 844|int   FileX_copyPickup2( const char* to_path, const char* from_path,
 845|  int startPos, int endPos, FileX_CallBack callback, void* obj )
 846|{
 847|  char  root_path[4];
 848|  FILE*  to_file;
 849|  FILE*  from_file;
 850|  int    size, leftSize;
 851|  int    now = 0, all;
 852|
 853|  if ( endPos == FILEX_TO_FULL ) {
 854|    FileX_FreeSpc  spc;
 855|
 856|    FileX_FreeSpc_init( &spc );
 857|    strncpy( root_path, to_path, 3 );  root_path[3] = '\0';
 858|    ASSERT( root_path[1] == ':' );
 859|    FileX_FreeSpc_scan( &spc, root_path );
 860|    endPos = startPos + FileX_FreeSpc_getFreeSize( &spc ) +
 861|      FileX_FreeSpc_getUseFileSize( &spc, to_path );
 862|  }
 863|  else if ( endPos == FILEX_TO_LAST ) {
 864|    endPos = INT_MAX;
 865|  }
 866|
 867|  all = FileX_getSize( from_path );
 868|  if ( all < endPos )  all = endPos;
 869|  all -= startPos;
 870|
 871|  FileX_mkdir2( to_path, true );
 872|  to_file = FileX_open( to_path, "wb" );
 873|  from_file = FileX_open( from_path, "rb" );
 874|
 875|  fseek( from_file, startPos, SEEK_SET );
 876|  leftSize = endPos - startPos;
 877|  if ( callback != NULL )  callback( obj, now, all );
 878|  do {
 879|    size = fread( FileX_buf, 1, sizeof(FileX_buf), from_file );
 880|    if ( size > leftSize )  size = leftSize;
 881|    if ( fwrite( FileX_buf, 1, size, to_file ) != (unsigned)size ) {
 882|      fclose( to_file );  fclose( from_file );
 883|      remove( to_path );
 884|      FileX_bCopyFailed = true;
 885|      error2_1( FileX_Err_CannotWrite, "%s の書きこみに失敗しました。",
 886|        to_path );
 887|    }
 888|    leftSize -= size;
 889|    now += size;
 890|    if ( callback != NULL )  callback( obj, now, all );
 891|  } while ( size == sizeof(FileX_buf) );
 892|
 893|  fclose( to_file );
 894|  fclose( from_file );
 895|
 896|  return  now;
 897|}
 898|#endif
 899|#endif
 900|#endif
 901|#endif
 902|
 903| 
 904|/***********************************************************************
 905|  27. <<< [FileX_outPart] ファイルの一部を出力する >>> 
 906|【引数】
 907|  ・FILE*  out;       出力先
 908|  ・FILE*  in;        入力
 909|  ・int    in_start;  入力開始位置
 910|  ・int    in_over;   入力終了の次の位置
 911|【補足】
 912|・out と in は、バイナリファイルで開いてください。
 913|************************************************************************/
 914|void  FileX_outPart( FILE* out, FILE* in, int in_start, int in_over )
 915|{
 916|  int   leftSize = in_over - in_start;
 917|  int   size;
 918|  char  buf[2048];
 919|
 920|  #if ERRORS_DEBUG_FALSE
 921|    Errors_printf( "in_start = %d, in_over = %d", in_start, in_over );
 922|    fprintf( out, "------------------------in_start = %d, in_over = %d\n", in_start, in_over );
 923|  #endif
 924|
 925|  ASSERT( in_start <= in_over );
 926|
 927|  fseek( in, in_start, SEEK_SET );
 928|  size = ( leftSize < sizeof(buf) ) ? leftSize : sizeof(buf);
 929|
 930|  do {
 931|    size = fread( buf, 1, size, in );
 932|    if ( fwrite( buf, 1, size, out ) != (unsigned)size ) {
 933|      error2_0( FileX_Err_CannotWrite, "書きこみに失敗しました。" );
 934|    }
 935|    /* leftSize -= size; */
 936|  } while ( size == sizeof(buf) );
 937|}
 938| 
 939|/*************************************************************************
 940|  28. <<< [FileX_copyFolder] フォルダごとコピーする >>> 
 941|【引数】
 942|  ・bool  bSub;   サブフォルダもコピーする
 943|【補足】
 944|・コピー先のフォルダに含まれるファイル名が一致するときのみファイルを上書きします。
 945|・書きこみに失敗したら、エラーになり、書き込み中だったコピー先のファイルは
 946|  削除されます。すでに書きこんだファイルはそのまま残ります。
 947|**************************************************************************/
 948|#ifdef  USES_FILEFIND
 949|#ifdef  USES_NESTFIND
 950|#if  defined(USES_STDPLUS) && defined(USES_STRX)
 951|#if  defined(USES_BIGSTACK) && defined(USES_EXCEPT3) && defined(USES_TIMEDATE)
 952|#if  defined(WIN32) || defined(FOR_DOS32)
 953|void  FileX_copyFolder( const char* to_path, const char* from_path,
 954|  bool bSub )
 955|{
 956|  NestFind  find;
 957|  char  from_path2[_MAX_PATH];
 958|  char  to_path2[_MAX_PATH];
 959|
 960|  if ( FileX_isExist( to_path ) && ! FileX_isDir( to_path ) ) {
 961|    error2_1( FileX_Err_CannotWrite, "%s の書きこみに失敗しました。",
 962|      to_path );
 963|  }
 964|  FileX_mkdir2( to_path, 0 );
 965|
 966|#if 0
 967|  ASSERT( ! bSub );
 968|  FileFind_init( &find, from_path );
 969|  c_try {
 970|    while ( FileFind_next( &find ) == 0 ) {
 971|      if ( ! FileFind_isDir( &find ) ) {
 972|        char* fname = FileFind_getFName( &find );
 973|        StrX_cpyAbsPath( from_path2, fname, _MAX_PATH, from_path );
 974|        StrX_cpyAbsPath( to_path2, fname, _MAX_PATH, to_path );
 975|        if ( FileX_isExist( from_path2 ) )
 976|          FileX_copy( to_path2, from_path2 );
 977|      }
 978|    }
 979|  }
 980|  c_finally {
 981|    FileFind_finish( &find );
 982|  } c_end_finally;
 983|#else
 984|  NestFind_init( &find, from_path, false );
 985|  c_try {
 986|    while ( NestFind_next( &find ) ) {
 987|      char* fname = NestFind_getPath( &find );
 988|      StrX_cpyAbsPath( from_path2, fname, _MAX_PATH, from_path );
 989|      StrX_cpyAbsPath( to_path2, fname, _MAX_PATH, to_path );
 990|      if ( FileX_isExist( from_path2 ) )
 991|        FileX_copy( to_path2, from_path2 );
 992|    }
 993|  }
 994|  c_finally {
 995|    NestFind_finish( &find );
 996|  } c_end_finally;
 997|#endif
 998|}
 999|#endif
1000|#endif
1001|#endif
1002|#endif
1003|#endif
1004| 
1005|/*************************************************************************
1006|  29. <<< [FileX_removeFolder] フォルダごと削除する >>> 
1007|【補足】
1008|・バックアップを取ってから実行してください。
1009|・システム領域は削除しないで下さい。
1010|・ごみ箱には格納されません。
1011|**************************************************************************/
1012|#ifdef  USES_NESTFIND
1013|#ifdef  USES_WINX
1014|#ifdef  USES_EXCEPT3
1015|void  FileX_removeFolder( const char* path )
1016|{
1017|  NestFind  find;
1018|
1019|  #ifdef  NDEBUG
1020|    #ifdef  FOR_WIN32
1021|    {
1022|      char  s[_MAX_PATH];
1023|      if ( stricmp( path, WinX_getWindowsPath() ) == 0 )  error();
1024|      GetSystemDirectory( s, sizeof(s) );
1025|      if ( stricmp( path, s ) == 0 )  error();
1026|    }
1027|    #else
1028|    #endif
1029|  #endif
1030|
1031|  if ( ! FileX_isExist( path ) )  return;
1032|
1033|  NestFind_init( &find, path, true );
1034|  while ( NestFind_next( &find ) ) {
1035|    if ( FileX_isDir( NestFind_getAbsPath( &find ) ) )
1036|      _rmdir( NestFind_getAbsPath( &find ) );
1037|    else {
1038|      _chmod( NestFind_getAbsPath( &find ), _S_IREAD | _S_IWRITE );
1039|      remove( NestFind_getAbsPath( &find ) );
1040|    }
1041|  }
1042|  NestFind_finish( &find );
1043|
1044|  {
1045|    char s[_MAX_PATH];
1046|    _getcwd( s, sizeof(s) );
1047|    if ( stricmp( s, path ) == 0 )
1048|      _chdir( ".." );
1049|  }
1050|  if ( ! RemoveDirectory( path ) )  WinX_error();
1051|}
1052|#endif
1053|#endif
1054|#endif
1055| 
1056|/*************************************************************************
1057|  30. <<< [FileX_setReadOnly] ファイルの読み込み専用属性を変更する >>> 
1058|【引数】
1059|  ・char*  path;       読み込み専用属性を変更するファイルのパス
1060|  ・bool  bReadOnly;   設定する値(true=読み込み専用)
1061|**************************************************************************/
1062|#if  defined(USES_STDPLUS) && ( defined(FOR_WIN32) || defined(FOR_DOS32) )
1063|void  FileX_setReadOnly( const char* path, bool bReadOnly )
1064|{
1065|  bool  bSuccess;
1066|  DWORD  attr = GetFileAttributes( path );
1067|  if ( attr == 0xFFFFFFFF )
1068|    error();  /* ファイルが存在しないかも */
1069|
1070|  if ( bReadOnly )  attr |= FILE_ATTRIBUTE_READONLY;
1071|  else  attr &= ~FILE_ATTRIBUTE_READONLY;
1072|
1073|  bSuccess = SetFileAttributes( path, attr );
1074|  if ( ! bSuccess )  error();
1075|}
1076|#endif
1077| 
1078|/*************************************************************************
1079|  31. <<< [FileX_cat] ファイルを連結する >>> 
1080|**************************************************************************/
1081|void  FileX_cat( const char* to_path, const char* from_path )
1082|{
1083|  FILE*  to_file = FileX_open( to_path, "ab" );
1084|  FILE*  from_file = FileX_open( from_path, "rb" );
1085|  size_t  size;
1086|
1087|  do {
1088|    size = fread( FileX_buf, 1, sizeof(FileX_buf), from_file );
1089|    fwrite( FileX_buf, 1, size, to_file );
1090|  } while ( size == sizeof(FileX_buf) );
1091|
1092|  fclose( to_file );
1093|  fclose( from_file );
1094|}
1095|
1096|
1097| 
1098|/*************************************************************************
1099|  32. <<< [FileX_include] ファイルを埋めこむ >>> 
1100|【引数】
1101|・int  mode;   to のモード{テキスト='t', バイナリ='b'}
1102|**************************************************************************/
1103|void  FileX_include( FILE* to, const char* from_path, int mode )
1104|{
1105|  FILE*  from_file;
1106|  size_t  size;
1107|  char  mode2[3];
1108|
1109|  strcpy( mode2, "rt" );  mode2[1] = mode;
1110|  from_file = FileX_open( from_path, mode2 );
1111|
1112|  do {
1113|    size = fread( FileX_buf, 1, sizeof(FileX_buf), from_file );
1114|    fwrite( FileX_buf, 1, size, to );
1115|  } while ( size == sizeof(FileX_buf) );
1116|
1117|  fclose( from_file );
1118|}
1119|
1120|
1121|
1122| 
1123|/*************************************************************************
1124|  33. <<< [FileX_mkdir2] フォルダを作成する >>> 
1125|【引数】
1126|  ・char* path;  実行中のフォルダからの相対パス、または絶対パス
1127|  ・int  bFile;  path は、ファイルなら 1, フォルダなら 0
1128|【補足】
1129|・作成するフォルダを格納するフォルダが無ければ、再帰的に
1130|  フォルダを作成します。
1131|  例:c:\a\b で a フォルダが無ければ、b フォルダだけでなく a フォルダも
1132|      作成します。
1133|・bFile を 1 にすると、path に指定したファイルを格納するフォルダを
1134|  作成します。
1135|**************************************************************************/
1136|#ifdef USES_STRX
1137|#ifdef USES_BIGSTACK
1138|void  FileX_mkdir2( const char* path, int bFile )
1139|{
1140|  static char   path2[_MAX_PATH];
1141|  static char*  p;  /* フォルダ区切り記号の位置(走査用) */
1142|
1143|  strcpy( path2, path );
1144|  StrX_getRunFullPath( path2, path2, _MAX_PATH - 1 );
1145|  if ( bFile )  StrX_cutFName( path2 );
1146|  StrX_cutLastOf2( path2, StrX_DirMark_char );
1147|
1148|  if ( path2[1] == ':' )   p = path2 + 2;
1149|  else                     p = path2 - 1;
1150|
1151|  while ( (p= StrX_strchr2( p + 1, StrX_DirMark_char )) != NULL ) {
1152|    *p = '\0';
1153|    if ( ! FileX_isDir( path2 ) )
1154|      _mkdir( path2 );   /* フォルダを格納するフォルダを作成 */
1155|    *p = StrX_DirMark_char;
1156|  }
1157|
1158|  if ( bFile ) {
1159|    strcpy( path2, path );
1160|    StrX_cutFName( path2 );
1161|    _mkdir( path2 );
1162|  }
1163|  else {
1164|    _mkdir( path );
1165|  }
1166|}
1167|#endif  /* #ifdef USES_BIGSTACK */
1168|#endif  /* USES_STRX */
1169|
1170|
1171| 
1172|/*************************************************************************
1173|  34. <<< [FileX_backup] ファイルのバックアップをとる >>> 
1174|【補足】
1175|・backup フォルダを作成して、そこに「移動」します。
1176|・backup フォルダには最新のバックアップと最古のバックアップが存在する
1177|  ようになります。
1178|・バックアップ後の(最新の)ファイルパスは、FileX_toBackupPath 関数から
1179|  取得します。
1180|・path のファイルが存在しない場合、何もしません。
1181|**************************************************************************/
1182|#if  defined(USES_STDPLUS) && defined(USES_STRX)
1183|#if  defined(USES_BIGSTACK) && defined(USES_EXCEPT3) && defined(USES_TIMEDATE)
1184|#if  defined(WIN32) || defined(FOR_DOS32)
1185|void  FileX_backup( const char* path )
1186|{
1187|  int  i;
1188|  char  s[_MAX_PATH];
1189|  #ifdef  USES_TIMEDATE
1190|    char  s2[_MAX_PATH];
1191|    time_t  t;
1192|    time_t  today;
1193|    struct tm*  tm;
1194|  #endif
1195|
1196|  if ( FileX_isExist( path ) ) {
1197|
1198|    /* バックアップを格納するフォルダを作成する */
1199|    for ( i = 0; ; i++ ) {
1200|      StrX_cpyFolder( s, path );
1201|      StrX_addFName( s, "backup" );
1202|      if ( i >= 1 )  sprintf( strchr( s, '\0' ), "%d", i );
1203|      if ( FileX_isDir( s ) )  break;
1204|      if ( FileX_isExist( s ) )  continue;
1205|      if ( _mkdir( s ) == -1 )
1206|        error2_1( FileX_Err_CannotMkdir, "フォルダ %s が作成できませんでした", s );
1207|      if ( FileX_isDir( s ) )  break;
1208|    }
1209|
1210|    /* ファイルをバックアップフォルダにコピーする(最新のバックアップ) */
1211|    StrX_addFName( s, StrX_refFName( path ) );
1212|    FileX_copy( s, path );
1213|    FileX_setReadOnly( s, false );  /* 上書きできるようにする */
1214|
1215|    /* ファイルをバックアップフォルダに移動する(本日最古のバックアップ) */
1216|    #ifdef  USES_TIMEDATE
1217|      strcpy( s2, s );  strcat( s2, "~" );
1218|      if ( ! FileX_isExist( s2 ) ) {
1219|        FileX_copy( s2, s );
1220|      }
1221|      else {
1222|        FileX_getUpdate( s2, &t );
1223|        time( &today );  tm = localtime( &today );
1224|        TimeDate_set( &today, tm->tm_year + 1900, tm->tm_mon + 1,
1225|          tm->tm_mday, 0,0,0 );
1226|        if ( difftime( t, today ) <= 0 )
1227|          FileX_copy( s2, s );
1228|      }
1229|    #endif
1230|
1231|    /* ファイルをバックアップフォルダに移動する(最古のバックアップ) */
1232|    strcat( s, "~~" );
1233|    rename( path, s );
1234|  }
1235|}
1236|#endif
1237|#endif
1238|#endif
1239|
1240| 
1241|/*************************************************************************
1242|  35. <<< [FileX_restoreIfSame] もし内容に変更が無かったら、バックアップした日付に戻す >>> 
1243|【補足】
1244|・FileX_backup でバックアップしたファイルと比較し、内容が同じなら、
1245|  更新日時を戻します。
1246|**************************************************************************/
1247|#if  defined(USES_STDPLUS) && defined(USES_STRX)
1248|#if  defined(USES_BIGSTACK) && defined(USES_EXCEPT3) && defined(USES_TIMEDATE)
1249|#if  defined(WIN32) || defined(FOR_DOS32)
1250|void  FileX_restoreIfSame( const char* path )
1251|{
1252|  time_t  date;
1253|  char  back_path[_MAX_PATH];
1254|
1255|  strcpy( back_path, path );
1256|  FileX_toBackupPath( back_path );
1257|
1258|  if ( ! FileX_isDiff( path, back_path ) ) {
1259|    FileX_getUpdate( back_path, &date );
1260|    FileX_setUpdate( path, &date );
1261|  }
1262|}
1263|#endif
1264|#endif
1265|#endif
1266| 
1267|/*************************************************************************
1268|  36. <<< [FileX_toBackupPath] ファイルのバックアップのパスに変更する >>> 
1269|【引数】
1270|  ・char*  path;   FileX_backup 関数に渡した引数
1271|【補足】
1272|・FileX_backup 関数で移動した先のパスを取得します。
1273|**************************************************************************/
1274|#ifdef  USES_STRX
1275|void  FileX_toBackupPath( char* path )
1276|{
1277|  StrX_cdFName( path, "backup" );
1278|}
1279|#endif
1280|
1281|
1282| 
1283|/*************************************************************************
1284|  37. <<< [FileX_write] 指定データをそのままファイルにする(バックアップ付き) >>> 
1285|【引数】
1286|  ・char*  flag;   "wb" または "wt"
1287|**************************************************************************/
1288|#if  defined(USES_STDPLUS) && defined(USES_STRX)
1289|#if  defined(USES_BIGSTACK) && defined(USES_EXCEPT3) && defined(USES_TIMEDATE)
1290|#if  defined(WIN32) || defined(FOR_DOS32)
1291|void  FileX_write( const char* path, const char* flag, void* data, int size )
1292|{
1293|  FILE*  f;
1294|
1295|  ASSERT( strchr( flag, 'r' ) == NULL );
1296|
1297|  FileX_backup( path );
1298|  FileX_mkdir2( path, true );
1299|  f = FileX_open( path, flag );
1300|  fwrite( data, 1, size, f );
1301|  fclose( f );
1302|}
1303|#endif
1304|#endif
1305|#endif
1306|
1307| 
1308|/*************************************************************************
1309|  38. <<< [FileX_read0] ファイルの内容をそのままデータにする >>> 
1310|【引数】
1311|  ・char*  flag;   "wb" または "wt"
1312|  ・void*  data;   データを格納する領域の先頭アドレス
1313|  ・int  size;     data のサイズ
1314|  ・int  返り値;   ファイルサイズ
1315|【補足】
1316|・データの末尾には '\0' が付きます。付ける必要が無ければ、標準関数の
1317|  fread が使えます。
1318|・返り値(ファイルサイズ)が size より大きいときは、size - 1 まで
1319|  読み込みます。
1320|**************************************************************************/
1321|#ifdef  USES_STRX
1322|int  FileX_read0( const char* path, const char* flag, void* data, int size )
1323|{
1324|  FILE*  f;
1325|  int  fsize;
1326|
1327|  if ( strchr( flag, 'w' ) != NULL || strchr( flag, 'a' ) != NULL )
1328|    { error();  return 0; }
1329|
1330|  fsize = FileX_getSize( path );
1331|  f = FileX_open( path, flag );
1332|  if ( fsize < size ) {
1333|    fsize = fread( data, 1, fsize, f );
1334|    ((char*)data)[ fsize ] = '\0';
1335|  }
1336|  else {
1337|    size = fread( data, 1, size * 2, f );
1338|    ((char*)data)[ size ] = '\0';
1339|  }
1340|  fclose( f );
1341|
1342|  return  fsize;
1343|}
1344|#endif
1345| 
1346|#if  defined(FOR_WIN32) || defined(FOR_DOS32) 
1347| 
1348|/*--------------------------------------------------------------------*/
1349|/* 39. <<<◆(FileX_UniRead) UNICODE ファイルを Shift-JIS として読み込むフィルタ >>> */ 
1350|/*--------------------------------------------------------------------*/
1351|
1352| 
1353|/***********************************************************************
1354|  40. <<< [FileX_UniRead_init] 読み込むファイルにフィルタをかける >>> 
1355|【引数】
1356|  ・char*  path;    読み込むファイルのパス
1357|  ・char*  返り値;  代わりに開くファイルパス、fopen 等に指定する
1358|【補足】
1359|・通常のファイル・オープンからクローズまでの外を FileX_UniRead_init と
1360|  FileX_UniRead_finish で囲んでください。その際、通常のファイル・
1361|  オープンに使うファイルパスは、本関数の返り値を指定してください。
1362|・Shift JIS でフォーマットされた一時ファイルを作成して、そのパスを返します。
1363|・path は UNICODE ファイルでなくても構いません。そのとき、一時ファイルは
1364|  作成しません。
1365|************************************************************************/
1366|char*  FileX_UniRead_init( FileX_UniRead* m, const char* path )
1367|{
1368|  ERRORS_INITCHK( m, 0 );
1369|
1370|  if ( FileX_isUnicodeFIle( path ) ) {
1371|    FileX_getTmpPath( "unitmp", m->tmp_path );
1372|    FileX_copyUni2SJis( m->tmp_path, path );
1373|    return  m->tmp_path;
1374|  }
1375|  else {
1376|    m->tmp_path[0] = '\0';
1377|    return  (char*)path;
1378|  }
1379|}
1380|
1381|
1382|
1383| 
1384|/***********************************************************************
1385|  41. <<< [FileX_UniRead_finish] 読み込むファイルのフィルタを除く >>> 
1386|************************************************************************/
1387|void  FileX_UniRead_finish( FileX_UniRead* m )
1388|{
1389|  ERRORS_INITCHK( m, 1 );
1390|
1391|  if ( m->tmp_path[0] != '\0' )
1392|    remove( m->tmp_path );
1393|}
1394|
1395|
1396| 
1397|/***********************************************************************
1398|  42. <<< [FileX_isUnicodeFIle] UNICODE のテキストファイルかどうかを返す >>> 
1399|************************************************************************/
1400|bool  FileX_isUnicodeFIle( const char* path )
1401|{
1402|  FILE*  f;
1403|  unsigned int    size;
1404|  unsigned short  buf;
1405|
1406|  f = FileX_open( path, "rb" );
1407|
1408|  size = fread( &buf, 1, 2, f );
1409|  fclose( f );
1410|
1411|  return  ( size == 2 && buf == 0xFEFF );
1412|}
1413|
1414| 
1415|/***********************************************************************
1416|  43. <<< [FileX_copyUni2SJis] UNICODE のファイルを Shift JIS に変換コピーする >>> 
1417|************************************************************************/
1418|void   FileX_copyUni2SJis( const char* toSjisPath, const char* fromUniPath )
1419|{
1420|  short* p;
1421|  FILE*  from_file;
1422|  FILE*  to_file;
1423|  unsigned int    size, size2;
1424|  unsigned short  buf[2048];
1425|  unsigned char   buf2[4096];
1426|
1427|  /* ファイルを開く */
1428|  to_file = FileX_open( toSjisPath, "wb" );
1429|  if ( to_file == NULL )  Errors_errorStdlib();
1430|  from_file = FileX_open( fromUniPath, "rb" );
1431|  ASSERT( from_file != NULL );
1432|
1433|  /* UNICODE ファイルのヘッダをチェックする */
1434|  size = fread( buf, 1, 2, from_file );
1435|  if ( size < 2 || *buf != 0xFEFF ) {
1436|    fclose( to_file );  fclose( from_file );
1437|    error2_0( FileX_Err_NotUnicodeFile, "UNICODE ファイルではありません" );
1438|  }
1439|
1440|  /* ファイルの内容をコピーする */
1441|  do {
1442|    size = fread( buf, 1, sizeof(buf) - 2, from_file );
1443|    p = (short*)( (char*)buf + size );  *p = (short)0;
1444|    StrX_unicode2sjis( buf2, buf, sizeof(buf2) );
1445|    size2 = strlen( buf2 );
1446|    if ( fwrite( buf2, 1, size2, to_file ) != size2 ) {
1447|      fclose( to_file );  fclose( from_file );
1448|      remove( toSjisPath );
1449|      FileX_bCopyFailed = true;
1450|      error2_1( FileX_Err_CannotWrite, "%s の書きこみに失敗しました。",
1451|        toSjisPath );
1452|    }
1453|  } while ( size == sizeof(buf) - 2 );
1454|
1455|  /* ファイルを閉じる */
1456|  fclose( to_file );
1457|  fclose( from_file );
1458|}
1459|
1460| 
1461|/*--------------------------------------------------------------------*/
1462|/* 44. <<<◆(FileX_UniWrite) Shift-JIS 形式で書き込む UNICODE ファイルフィルタ >>> */ 
1463|/*--------------------------------------------------------------------*/
1464| 
1465|/***********************************************************************
1466|  45. <<< [FileX_UniWrite_init] 書き込むファイルにフィルタをかける >>> 
1467|【引数】
1468|  ・char*  path;    書き込むファイルのパス
1469|  ・char*  返り値;  代わりに開くファイルパス、fopen 等に指定する
1470|【補足】
1471|・通常のファイル・オープンからクローズまでの外を FileX_UniWrite_init と
1472|  FileX_UniWrite_finish で囲んでください。その際、通常のファイル・
1473|  オープンに使うファイルパスは、本関数の返り値を指定してください。
1474|・FileX_UniWrite_finish で、作成した一時ファイルを UNICODE へ変換します。
1475|************************************************************************/
1476|char*  FileX_UniWrite_init( FileX_UniWrite* m, const char* path )
1477|{
1478|  ERRORS_INITCHK( m, 0 );
1479|
1480|  FileX_getTmpPath( "unitmp", m->tmp_path );
1481|  strcpy( m->path, path );
1482|
1483|  return  m->tmp_path;
1484|}
1485|
1486|
1487|
1488| 
1489|/***********************************************************************
1490|  46. <<< [FileX_UniWrite_finish] 書き込むファイルのフィルタを除く >>> 
1491|************************************************************************/
1492|void   FileX_UniWrite_finish( FileX_UniWrite* m )
1493|{
1494|  ERRORS_INITCHK( m, 1 );
1495|
1496|  FileX_copySJis2Uni( m->path, m->tmp_path );
1497|  remove( m->tmp_path );
1498|}
1499|
1500|
1501| 
1502|/***********************************************************************
1503|  47. <<< [FileX_copySJis2Uni] Shift JIS のファイルを UNICODE に変換コピーする >>> 
1504|************************************************************************/
1505|void   FileX_copySJis2Uni( const char* toUniPath, const char* fromSJisPath )
1506|{
1507|  char*  p;
1508|  FILE*  from_file;
1509|  FILE*  to_file;
1510|  unsigned int    size, size2;
1511|  unsigned char   buf[2048];
1512|  unsigned short  buf2[2048];
1513|
1514|  /* ファイルを開く */
1515|  to_file = FileX_open( toUniPath, "wb" );
1516|  if ( to_file == NULL )  Errors_errorStdlib();
1517|  from_file = FileX_open( fromSJisPath, "rb" );
1518|  ASSERT( from_file != NULL );
1519|
1520|  /* UNICODE ファイルのヘッダを出力する */
1521|  *buf2 = 0xFEFF;
1522|  if ( fwrite( buf2, 1, 2, to_file ) != 2 ) {
1523|    fclose( to_file );  fclose( from_file );
1524|    remove( toUniPath );
1525|    FileX_bCopyFailed = true;
1526|    error2_1( FileX_Err_CannotWrite, "%s の書きこみに失敗しました。",
1527|      toUniPath );
1528|  }
1529|
1530|  /* ファイルの内容をコピーする */
1531|  do {
1532|    size = fread( buf, 1, sizeof(buf) - 1, from_file );
1533|
1534|    p = buf + size - 1;  *(p + 1) = '\0';
1535|    if ( StrX_isSJis2byte( buf, p ) )  *p = '\0';
1536|    StrX_sjis2unicode( buf2, buf, sizeof(buf2) );
1537|    size2 = wcslen( buf2 ) * 2;
1538|
1539|    if ( fwrite( buf2, 1, size2, to_file ) != size2 ) {
1540|      fclose( to_file );  fclose( from_file );
1541|      remove( toUniPath );
1542|      FileX_bCopyFailed = true;
1543|      error2_1( FileX_Err_CannotWrite, "%s の書きこみに失敗しました。",
1544|        toUniPath );
1545|    }
1546|  } while ( size == sizeof(buf) - 1 );
1547|
1548|  /* ファイルを閉じる */
1549|  fclose( to_file );
1550|  fclose( from_file );
1551|}
1552| 
1553|#endif 
1554| 
1555|/*--------------------------------------------------------------------*/
1556|/* 48. <<<◆(FileX_CurDir) カレントフォルダ・スタック >>> */ 
1557|/*--------------------------------------------------------------------*/
1558|
1559|
1560| 
1561|/*************************************************************************
1562|  49. <<< [FileX_CurDir_init] カレントフォルダをスタック的に変更する >>> 
1563|【引数】
1564|  ・char*  path;  新しいカレントフォルダ、またはファイルのパス
1565|【補足】
1566|・この関数は、BigStack_start から BigStack_end の間に入れる必要があります。
1567|・m は、この関数を呼び出すたびに、新しくスタック変数として用意してください。
1568|・path にファイルを指定した場合、そのファイルを格納しているフォルダに
1569|  カレントフォルダを変更します。
1570|・path は、相対パスでも絶対パスでも構いません。
1571|・相対パスで path に指定したファイルを開くときは、新しいカレントフォルダを
1572|  指定することに注意してください。
1573|【例】
1574|  void  func( char* fname )
1575|  {
1576|     FileX_CurDir  cur;
1577|
1578|     BigStack_start();
1579|     FileX_CurDir_init( &cur, fname );  // fname のあるフォルダへ
1580|     FileX_open( StrX_refFName( fname ), "rt" );  // カレントで開く
1581|      ...
1582|     FileX_CurDir_finish( &cur );  // 戻す
1583|     BigStack_end();
1584|  }
1585|**************************************************************************/
1586|#ifdef USES_STRX
1587|#ifdef USES_BIGSTACK
1588|void  FileX_CurDir_init( FileX_CurDir* m, const char* path )
1589|{
1590|  char*  newDir;
1591|
1592|  /* カレント・フォルダをとっておく */
1593|  m->curPath = BigStack_alloc( _MAX_PATH );
1594|  _getcwd( m->curPath, _MAX_PATH );
1595|
1596|  /* カレント・フォルダを変更する */
1597|  if ( FileX_isDir( path ) ) {
1598|    _chdir( path );
1599|  }
1600|  else {
1601|    BigStack_start();
1602|    newDir = BigStack_alloc( _MAX_PATH );
1603|    strcpy( newDir, path );
1604|    StrX_cutFName( newDir );
1605|    _chdir( newDir );
1606|    BigStack_end();
1607|  }
1608|}
1609|#endif /* USES_BIGSTACK */
1610|#endif /* USES_STRX */
1611|
1612|
1613| 
1614|/*************************************************************************
1615|  50. <<< [FileX_CurDir_finish] カレントフォルダを戻す >>> 
1616|【補足】
1617|・この関数は、BigStack_start から BigStack_end の間に入れる必要があります。
1618|**************************************************************************/
1619|#ifdef USES_BIGSTACK
1620|void  FileX_CurDir_finish( FileX_CurDir* m )
1621|{
1622|  _chdir( m->curPath );
1623|}
1624|#endif /* USES_BIGSTACK */
1625|
1626|
1627| 
1628|/*---------------------------------------------------------------------*/
1629|/* 51. <<<◆(FileX_FreeSpc) ディスクの空き容量 >>> */ 
1630|/*---------------------------------------------------------------------*/
1631|
1632|#ifdef  FILEX_FREESIZE
1633|  FileX_FreeSpc  FileX_freeSpcSym;
1634|#endif
1635|
1636| 
1637|/*************************************************************************
1638|  52. <<< [FileX_FreeSpc_init] 初期化する >>> 
1639|【補足】
1640|・FileX_FreeSpc_scan してから、空き容量の変数が有効になります。
1641|**************************************************************************/
1642|void  FileX_FreeSpc_init( FileX_FreeSpc* m )
1643|{
1644|  m->sectorsPerCluster = 0;
1645|  m->bytesPerSector = 0;
1646|  m->numberOfFreeClusters = 0;
1647|  m->totalNumberOfClusters = 0;
1648|}
1649|
1650| 
1651|/*************************************************************************
1652|  53. <<< [FileX_FreeSpc_scan] 空き容量をディスクから取得する >>> 
1653|【引数】
1654|  ・char*  root_path;  ルートのパス(例:"c:\\")
1655|【補足】
1656|・取得したサイズは、FileX_FreeSpc_getFreeSize 関数などから取得します。
1657|・FILEX_FREESIZE を #define すると、空き容量をシミュレートできます。
1658|  FileX_freeSpcSym グローバル変数(FileX_FreeSpc型)のメンバ変数に
1659|  設定してください。
1660|**************************************************************************/
1661|#ifdef  WIN32
1662|void  FileX_FreeSpc_scan( FileX_FreeSpc* m, const char* root_path )
1663|{
1664|  #ifdef  FILEX_FREESIZE
1665|    *m = FileX_freeSpcSym;
1666|  #else
1667|    if ( ! GetDiskFreeSpace( root_path, &m->sectorsPerCluster,
1668|        &m->bytesPerSector, &m->numberOfFreeClusters,
1669|        &m->totalNumberOfClusters ) ) {
1670|      m->sectorsPerCluster = 0;
1671|      m->bytesPerSector = 0;
1672|      m->numberOfFreeClusters = 0;
1673|      m->totalNumberOfClusters = 0;
1674|    }
1675|  #endif
1676|}
1677|#endif
1678| 
1679|/*************************************************************************
1680|  54. <<< [FileX_FreeSpc_getFreeSize] 空き容量を計算する >>> 
1681|【補足】
1682|・書き込みできるかどうか判断するときは、上書きすることを考慮に入れてください。
1683|  → FileX_FreeSpc_getUseFileSize 関数
1684|・1KB = 1024byte, 1MB = 1024KB
1685|**************************************************************************/
1686|int  FileX_FreeSpc_getFreeSize( FileX_FreeSpc* m )
1687|{
1688|  return  m->sectorsPerCluster *
1689|    m->bytesPerSector * m->numberOfFreeClusters;
1690|}
1691|
1692| 
1693|/*************************************************************************
1694|  55. <<< [FileX_FreeSpc_getTotalSize] 総容量を計算する >>> 
1695|【補足】
1696|・1KB = 1024byte, 1MB = 1024KB, 1GB = 1024MB
1697|**************************************************************************/
1698|int  FileX_FreeSpc_getTotalSize( FileX_FreeSpc* m )
1699|{
1700|  return  m->sectorsPerCluster *
1701|    m->bytesPerSector * m->totalNumberOfClusters;
1702|}
1703|
1704| 
1705|/*************************************************************************
1706|  56. <<< [FileX_FreeSpc_getUseFileSize] ファイルの使用サイズを返す >>> 
1707|【引数】
1708|  ・FileX_FreeSpc*  m;  ドライブの空き容量
1709|  ・char*  path;           ファイルパス
1710|  ・int  返り値;           ファイルの使用サイズ
1711|【補足】
1712|・m を初期化してから使用してください。
1713|・ファイルシステムでは、クラスタ単位で領域を扱っているため、実際の
1714|  ファイルサイズより大きめの領域を使用しています。その領域のサイズを
1715|  返します。
1716|・指定したファイルが存在しない場合は、0 を返します。
1717|・m と path のドライブが異なる場合、path のファイルを m の
1718|  ドライブに格納したときの使用サイズを返します。
1719|**************************************************************************/
1720|#ifdef  USES_EXCEPT3
1721|int  FileX_FreeSpc_getUseFileSize( FileX_FreeSpc* m, const char* path )
1722|{
1723|  int  size;
1724|  int  nCluster;
1725|  int  bytesPerCluster = m->sectorsPerCluster * m->bytesPerSector;
1726|
1727|  if ( ! FileX_isExist( path ) )  return  0;
1728|  size = FileX_getSize( path );
1729|  nCluster = FileX_FreeSpc_culcNCluster( m, size );
1730|  return  nCluster * bytesPerCluster;
1731|}
1732|#endif
1733|
1734| 
1735|/*************************************************************************
1736|  57. <<< [FileX_FreeSpc_culcNCluster] 指定サイズが使うクラスタ数を返す >>> 
1737|【引数】
1738|  ・int  size;  ファイルのサイズ(バイト)
1739|**************************************************************************/
1740|int  FileX_FreeSpc_culcNCluster( FileX_FreeSpc* m, int size )
1741|{
1742|  int  bytesPerCluster = m->sectorsPerCluster * m->bytesPerSector;
1743|
1744|  return  ( size + bytesPerCluster - 1 ) / bytesPerCluster;
1745|}
1746|
1747| 
1748|