/*-------------------------------------------------------------- 決め打ちファイル名が LIST.TMP , NEWLIST.TMP , LIST.M3U なので気をつけて・・・ っていうか私が気をつけないと・・・ --------------------------------------------------------------*/ #include "file.h" #include #define SUCCESS 1 #define FAIL (-1) #define NOMBERING 2 /* 自分用のパディング */ int FileReverce( FILE *fp ); inline int GetFileName( char *pathname , char *onlyname ); long DeleteSameFile( FILE *fp_listtmp , char pathname[] ,const char *filename ); int main(void) { FILE *fp_listtmp; /* ren出きるように既存のファイルを消しておく */ remove("LIST.M3U"); /*MP3ファイル名を読み込むので,バッファサイズはFILENAME_MAXである */ char buffer[FILENAME_MAX]; int flag = 1; /* NEWLIST.TMPと、LIST.TMPどちらを使っているか */ long position; /* ファイル位置指定子の格納 */ /* DOSでの実行 DOSコマンドで考えて!*/ system("DIR *.mp3 /A:-D /O:-N /S /B > LIST.TMP"); /* ファイル名は決め打ち */ fp_listtmp = Efopen( "LIST.TMP" , "r+", "LIST.TMP Open Error" ); /* [EOF]が出てくるまで続くループ */ /* DOSのdirの出力では必ず最後に改行があるのでそれに依存したPGM */ for(;;){ Efgets( buffer , FILENAME_MAX , fp_listtmp , "File Read Error" ); /* LIST.TMPを作った際には確実に[EOF]の前に改行があるので、ここで終了してもOK */ if(feof(fp_listtmp)!=0) break; if(flag == 1 ){ /* 同じファイル名がある部分を消していく */ position = DeleteSameFile( fp_listtmp , buffer ,"NEWLIST.TMP" ); fp_listtmp = Efopen( "NEWLIST.TMP" , "r+", "File Open Error" ); /* ファイル位置指定子の位置を元に戻しておく */ Efseek( fp_listtmp , position , 's' , "Skip Error" ); flag *= -1; } else{ /* 同じファイル名がある部分を消していく */ position = DeleteSameFile( fp_listtmp , buffer , "LIST.TMP"); fp_listtmp = Efopen( "LIST.TMP" , "r+" , "File Open Error" ); /* ファイル位置指定子の位置を元に戻しておく */ Efseek( fp_listtmp , position , 's' , "Skip Error" ); flag *= -1; } } /*クローズ*/ FileReverce( fp_listtmp ); /* テンポラリファイルの削除 */ remove( "LIST.TMP" ); remove( "NEWLIST.TMP" ); return SUCCESS; } /*************************************************************************************** 同じファイル名を持つ行以外をコピーする関数。 第一引数のファイルの内容で、第二引数とおなじ部分を持つ行以外を 第三引数のファイルにコピーする。 全てのファイルポインタはクローズして終わる。 ファイルポインタを受け取ったときのファイル指定子を返値に持つ。 この関数を交互に使うことで、無駄な物を削るという処理を行う。 ***************************************************************************************/ long DeleteSameFile( FILE *fp_listtmp , char pathname[] ,const char *filename ) { FILE *fp_newlisttmp; char buffer[FILENAME_MAX], bufname[FILENAME_MAX], onlyname[FILENAME_MAX]; /* 最初にファイル位置指定子の場所を記憶しておく。 */ const long position = ftell( fp_listtmp ); /* ファイル位置指定子の初期化(先頭へ) */ Efseek( fp_listtmp , 0 , 's' , "Skip Error in DeleteSameFile" ); /* 「NEWLIST.TMP」を開く。*/ fp_newlisttmp = Efopen( filename ,"w" , "File Open Error in DeleteSameFile" ); GetFileName( pathname , onlyname ); /*「LIST.TMP」に[EOF]が出てくるまで続くループ */ /* DOSのdirの出力では必ず最後に改行があるのでそれに依存したPGM */ for(;;){ /* 「LIST.TMP」から一行を読み込む。*/ Efgets(buffer ,FILENAME_MAX ,fp_listtmp , "File Read Error in DeleteSameFile"); /* LIST.TMPを作った際には確実に[EOF]の前に */ /* 改行があるので、ここで終了してもOK */ if(feof(fp_listtmp)!=0) break; /* 同じファイル名の行以外をNEWLIST.TMPにコピーする。 */ /* このとき、position以前の物は変化がないことは自明。 */ GetFileName( buffer , bufname ); if( strcmp( bufname , onlyname ) != 0 ) Efputs( buffer , fp_newlisttmp ,"File Write Error in DeleteSameFile" ); else if( strcmp( buffer , pathname ) == 0 ) Efputs( buffer , fp_newlisttmp ,"File Write Error in DeleteSameFile" ); } /* fileクローズ*/ Efclose( fp_listtmp , "File Close Error in DeleteSameFile" ); Efclose( fp_newlisttmp , "File Close Error in DeleteSameFile" ); return position; } /*************************************************************************************** パスを含むファイル名から、ファイル名のみを抜き出す関数。 \\が一番最後に出てきたところ以降をファイル名と見なす。 自分が使うために、NOMBERINGを使用している。 これは、自分のファイル名の先頭に2桁のナンバーを打っているため。 本来は別の関数でやる方が良いかも。 ***************************************************************************************/ inline int GetFileName( char *pathname , char *onlyname ) { const int length = strlen( pathname ); /* pathnameの長さ */ int pathend; pathend = length; /* pathnameのなかの最後の \ の位置 */ while( pathend >= 0 ){ if( *(pathname + pathend) == '\\' ) /* DOSの区切り文字は \ */ break; pathend--; } strcpy( onlyname , pathname + pathend + 1 + NOMBERING ); return SUCCESS; } #define MAX 1024 /*************************************************************************************** このリストは古い物が一番上に来るように設定されるので、 ファイルを行毎に、全て逆順になるようにする。 与えられたファイルポインタから全ての行を読み込んで、クローズ。 その後、改めて開いたファイルに全てを逆順に書き込み、クローズ。 返値は常にSUCCESS ***************************************************************************************/ int FileReverce( FILE *fp ) { char **ptr, /* 行毎を格納するための配列(ポインタ)へのポインタ */ buffer[FILENAME_MAX]; /* 1行を読み込むためのバッファ */ ptr = (char **)malloc( sizeof(char *) * MAX ); /* ポインタをMAX個数まで割り当てる */ if( ptr == NULL ){ printf( "Memory Open Error\n" ); exit( FAIL ); } Efseek( fp , 0 , 's' , "Initialize Error in FileReverce" ); /* ファイル指定しの初期化 */ /* ファイルを最初から行毎に読み込んでいって、そのサイズと同じだけの 領域をmalloc()によって作り、そこにコピー。 NULLのサイズ分だけは注意。 */ for( int k=0 ; k < MAX ; k++ ){ Efgets( buffer , FILENAME_MAX , fp , "File Read Error in FileReverce" ); if( feof( fp ) != 0 ) break; *(ptr + k) = (char *)malloc( sizeof( char ) * strlen( buffer ) + 1 ); /* NULLのサイズ分 +1 */ strcpy( *(ptr + k) , buffer ); } Efclose( fp , "File Close Error in FileReverce" ); /* ファイルを一度クローズ */ fp = Efopen( "LIST.M3U" , "w" , "File Open Error in FileReverce" ); for( k-- ; k >= 0 ; k-- ){ Efputs( *(ptr + k) , fp , "File Write Error in FileReverce" ); free( *(ptr + k) ); } free( ptr ); Efclose( fp , "File Close Error in FileReverce" ); return SUCCESS; }