//*****************************************************************************
// ListUpFiles.cpp : 指定のディレクトリ内の指定ファイルを全てリストアップする
//                   (そのディレクトリ内のみ、複数パス指定可)
//*****************************************************************************

#include "stdafx.h"

int ListUpFiles( char* ppath , char* bufp , int bufsize ) ;
int GetMultiFileFirst( char* ppath , char* pfilepath ) ;
int GetMultiFileNext( char* pfilepath ) ;
int MultiPathToEachPath( const char* sbuf , CString* pstr , int pstrcount ) ;
int GetStringParam( const char* sbuf , CString* pstr , int pstrcount ) ;
CString GetStringTopParam( BYTE* sbuf , int slen , int* pcheckedlen ) ;
void SeparatePath( CString& path , CString& purepath , CString& filename ) ;
int GetTheFileFirst( char* ppath , char* pfilepath ) ;
int GetTheFileNext( char* pfilepath ) ;
void FileLastSx( ) ;
int GetLastYenPos( BYTE* buf , int blen ) ;
int GetErrorCode( ) ;

#define MAXPARAMLEN             256
#define MAXMULTIPATHCOUNT       10  

#define C_SPACE                 ' '
#define C_QUOT                  '"'

static CString multipath[MAXMULTIPATHCOUNT] ;
static int multipathcount ;
static int nextmultipathindex ;

WIN32_FIND_DATA ffindt ;
HANDLE hffind ;

static char ppathsave[_MAX_PATH+1] ;

int g_pickupallfiles = TRUE ;   // TRUE:ディレクトリ、または圧縮以外のすべてのファイルをpickup(archive属性がoffだとpickupされない件の対応)、FALSE:従来通り

//*****************************************************************************
// 機能 : 指定のディレクトリ内の指定ファイルを全てリストアップする(ただしそのディレクトリ内のみ)。
//  入力 :  ppath = マルチ絶対パス("x:\xxx\xxx\filename filename1 filename2, ..."形式であること。filenameはワイルドカード可)
//                                              (例)"x:\xxx\xxx\*.wbr"
//            bufp = ファイルの絶対パス名を格納する領域へのポインタ
//            bufsize = bufpのサイズ
//  戻り値: 指定ファイルの個数、-1 の時はバッファオーバー。
//  注意 : bufpへの格納形式は次の通り。
//            x:\xxx\xxx\realfilename(NULL)
//              ----------------
//*****************************************************************************
int ListUpFiles( char* ppath , char* bufp , int bufsize )
{
    int i ;
    int count ;
    int len ;

    if ( GetMultiFileFirst( ppath , bufp ) != 0 )
        return 0 ;

    for ( i = 0 , count = 0 ; ; )
    {
        len = (int)strlen( (const char*)&bufp[i] ) ;
        i += len+1 ;
        count++ ;
        
        if ( i >= bufsize-(_MAX_PATH+1) )
        {
            FileLastSx( ) ;
            break ;

        }

        if ( GetMultiFileNext( &bufp[i] ) != 0)
            break ;

    }

    if ( i >= bufsize-(_MAX_PATH+1) )
        return -1 ;
    else
        return count ;

}


//*****************************************************************************
// 機能 : 指定のファイル名に一致する最初のファイルを見つけて戻す。
//  入力 : ppath = マルチ絶対パス("x:\xxx\xxx\filename filename1 filename2, ..."形式であること。filenameはワイルドカード可)
//            pfilepath = (見つかればここに、"x:\xxx\xxx\fff"形式で戻る)
//  戻り値: 0:OK , 1:ない
//  注意  :  エラー発生時は、1で戻る。
//*****************************************************************************
int GetMultiFileFirst( char* ppath , char* pfilepath )
{

    multipathcount = MultiPathToEachPath( (const char*)ppath , multipath , MAXMULTIPATHCOUNT ) ;
    if ( multipathcount == 0 )
    {
        ASSERT( FALSE ) ;
        return 1 ;

    }

    nextmultipathindex = 0 ;

    int i ;
    for ( i = nextmultipathindex ; i < multipathcount ; i++ )
    {
    
        if ( GetTheFileFirst( (char*)(const char*)multipath[i] , pfilepath ) == 0 )
            break ;

    }

    nextmultipathindex = i ;

    if ( i == multipathcount )
        return 1 ;
    else
        return 0 ;

}



//*****************************************************************************
// 機能 : 指定のファイル名に一致する次のファイルを見つけて戻す。
//  入力 :  pfilepath = (見つかればここに、"x:\xxx\xxx\fff"形式で戻る)
//  戻り値: 0:OK , 1:ない
//  注意 : GetTheFileFirstを事前に呼び、成功していること。
//  注意  :  エラー発生時は、1で戻る。
//*****************************************************************************
int GetMultiFileNext( char* pfilepath )
{

    if ( GetTheFileNext( pfilepath ) == 0 )
        return 0 ;

    if ( nextmultipathindex == multipathcount-1 )
        return 1 ;

    nextmultipathindex++ ;

    int i ;
    for ( i = nextmultipathindex ; i < multipathcount ; i++ )
    {
    
        if ( GetTheFileFirst( (char*)(const char*)multipath[i] , pfilepath ) == 0 )
            break ;

    }

    nextmultipathindex = i ;

    if ( i == multipathcount )
        return 1 ;
    else
        return 0 ;

}


//***************************************************************************
//  機能 :指定のマルチパス指定を解析し、フルパス配列にして戻す。
//  入力  :pstrcount = pstr[]の配列要素数
//  戻り値:取り出したフルパス配列の要素数
//  注意  :囲み記号ははずした形で戻す。
//          マルチパス指定は次のような形式とする。
//              フルパス指定 ファイル2 ファイル3, ----
//                  (注)ファイル2, ファイル3,..の前には \ マークはないこと!
//              フルパス指定 フルパス指定,.... 
//              (先頭は必ずフルパス指定、その後はファイル名のみまたはフルパス)
//          (例)
//              
//          c:\wk\*.c                   ---> c:\wk\*.c
//          c:\wk\*.c *.h               ---> c:\wk\*.c
//                                           *.h
//          "c:\wk\*.c *.h"             ---> c:\wk\*.c *.h
//          "c:\wk\*.c ""*.h"           ---> c:\wk\*.c "*.h    ---連続する"は単なる"と見なす
//***************************************************************************
int MultiPathToEachPath( const char* sbuf , CString* pstr , int pstrcount )
{
    
    int elementcount = GetStringParam( sbuf , pstr , pstrcount ) ;
    if ( elementcount == 0 )
        return 0 ;

    if ( elementcount == 1 )
        return 1 ;                  // FullPath指定のみ!


    CString purepath ;
    CString filename ;
    SeparatePath( pstr[0] , purepath , filename ) ;

    int i ;
    for ( i = 1 ; i < elementcount ; i++ )
    {
        CString wkstr = purepath ;
        CString wkfilename = pstr[i] ;
        int wkfilenamelen = wkfilename.GetLength( ) ;
        if ( wkfilenamelen > 2 && wkfilename[1] == ':' )
            NULL ;                      // 元々フルパスと解釈!!!
        else
        {

            if ( wkfilenamelen > 0 && wkfilename[0] == '\\' )
            {
                ASSERT( FALSE ) ;

                CString wkfilename2 = wkfilename.Right( wkfilenamelen-1 ) ;
                wkfilename = wkfilename2 ;

            }

            wkstr += wkfilename ;                   // c:\wk\ + xxxx.txt ----> c:\wk\xxxx.txt
            pstr[i] = wkstr ;

        }

    }

    return elementcount ;

}


//***************************************************************************
//  機能 :指定バッファの文字列を半角SPを区切りとした文字列に分解して戻す。
//          ""で囲まれている場合は、空白自体が文字列と見なされる。
//          ""で囲まれていない場合は、末尾の空白は無視
//  入力  :pstrcount = pstr[]の配列要素数
//  戻り値:取り出した文字列の個数
//  注意  :c:\wk\*.c                   ---> c:\wk\*.c
//          c:\wk\*.c *.h               ---> c:\wk\*.c
//                                           *.h
//          "c:\wk\*.c *.h"             ---> c:\wk\*.c *.h
//          "c:\wk\*.c ""*.h"           ---> c:\wk\*.c "*.h    ---連続する"は単なる"と見なす
//          MAXPARAMLENを越えるパラメータはMAXPARAMLEN+1以降が無視される
//***************************************************************************
int GetStringParam( const char* sbuf , CString* pstr , int pstrcount )
{
    int slen = (int)strlen( sbuf ) ;
    if ( slen == 0 )
        return 0 ;

    int i ;
    int k ;
    for ( i = 0 , k = 0 ; i < slen && k < pstrcount ; )
    {

        int checkedlen ;
        int restlen = slen - i ;
        CString estr = GetStringTopParam( (BYTE*)(&sbuf[i]) , restlen , &checkedlen ) ;
        if ( estr.IsEmpty( ) )
            break ;

        pstr[k] = estr ;
        k++ ;

        i += checkedlen ;
        for ( ; i < slen ; i++ )
        {
            if ( sbuf[i] != C_SPACE )
                break ;

        }

    }

    return k ;

}


//***************************************************************************
//  機能 :指定バッファから先頭の文字列を取り出して戻す。
//          半角SPを区切りとする。
//          ""で囲まれている場合は、空白自体が文字列と見なされる。
//  戻り値:取り出した文字列
//  注意  :c:\wk\*.c                   ---> c:\wk\*.c
//          c:\wk\*.c *.h               ---> c:\wk\*.c
//                                           *.h
//          "c:\wk\*.c *.h"             ---> c:\wk\*.c *.h
//          "c:\wk\*.c ""*.h"           ---> c:\wk\*.c "*.h    ---連続する"は単なる"と見なす
//          MAXPARAMLENを越える場合は、Emptyで戻る。
//          *pcheckedlenは取り出した文字列長より大の場合あり(途中に"xx"がある場合)
//***************************************************************************
CString GetStringTopParam( BYTE* sbuf , int slen , int* pcheckedlen )
{
    CString estr = "" ; 
    BYTE ebuf[MAXPARAMLEN+1] ;

    *pcheckedlen = 0 ;

    if ( slen == 0 )
        return estr ;

    int i ;
    int k ;
    int bSpaceOK = FALSE ;
    for ( i = 0 , k = 0 ; i < slen && k < MAXPARAMLEN ; i++ )
    {
        BYTE bt = sbuf[i] ;     
        
        if ( bt == C_SPACE )
        {
            if ( !bSpaceOK )
                break ;
            
            ebuf[k] = bt ;
            k++ ;
            continue ;

        }

        if ( bt == C_QUOT )
        {
            if ( i+1 < slen && sbuf[i+1] == C_QUOT )
            {               // 単なる文字と見なす!!!
                ebuf[k] = bt ;
                k++ ;
                i++ ;       // for 連続するC_QUOTをスキップ
                continue ;

            }

            if ( !bSpaceOK )
                bSpaceOK = TRUE ;
            else
                bSpaceOK = FALSE ;

            continue ;

        }

        ebuf[k] = bt ;
        k++ ;

    }

    *pcheckedlen = i ;

    if ( k == MAXPARAMLEN )
        return estr ;           // パラメータが長すぎる場合は、emptyで戻す!
    
    ebuf[k] = 0 ;               // set NULL 

    estr = (const char*)ebuf ;

    return estr ;

}


//***************************************************************************
//  機能 :指定のフルパス文字列からファイル名をその前までの部分に分解して戻す。
//  注意  :(例)
//              c:\wk\xxx.txt ----> c:\wk\     <------最後に\が付く!
//                                  xxx.txt
//***************************************************************************
void SeparatePath( CString& path , CString& purepath , CString& filename )
{
    purepath = "" ;
    filename = "" ;

    int plen = path.GetLength( ) ;
    if ( plen == 0 )
        return ;

    int pos = path.ReverseFind( '\\' ) ;
    if ( pos == -1 )
    {
        ASSERT( FALSE ) ;
        return ;

    }

    if ( pos == plen-1 )
    {
        purepath = path ;
        filename = "" ;
        return ;

    }

    purepath = path.Left( pos+1 ) ;     // \ を含めて取り出し
    filename = path.Right( plen-(pos+1) ) ;

}


//*****************************************************************************
// 機能 : 指定のファイル名に一致する最初のファイルを見つけて戻す。
//  入力 : ppath = 絶対パス("x:\xxx\xxx\filename"形式であること。filenameはワイルドカード可)
//            pfilepath = (見つかればここに、"x:\xxx\xxx\fff"形式で戻る)
//  戻り値: 0:OK , 1:ない , 2:エラー発生
//*****************************************************************************
int GetTheFileFirst( char* ppath , char* pfilepath )
{
    int i ;

    int len = (int)strlen( (const char*)ppath ) ;

    i = GetLastYenPos( (BYTE*)ppath , len ) ;

    ASSERT( i > 0 ) ;
    strncpy( ppathsave , (const char*)&ppath[0] , i+1 ) ;
    ppathsave[i+1] = 0 ;

    hffind = FindFirstFile( ppath , &ffindt ) ;

    if ( hffind == INVALID_HANDLE_VALUE )
        return GetErrorCode( ) ;

    for ( ; ; )
    {

        if ( g_pickupallfiles )
        {
            if ( !(ffindt.dwFileAttributes & (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_SYSTEM)) )
                break ;

        }
        else
        {
        
            if ( ffindt.dwFileAttributes & (FILE_ATTRIBUTE_NORMAL|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_ARCHIVE) )
                break ;

        }
    
        if ( !FindNextFile( hffind , &ffindt ) )
        {
            FileLastSx( ) ;
            return GetErrorCode( ) ;
        }
    }

    strcpy( pfilepath , ppathsave ) ;
    strcat( pfilepath , ffindt.cFileName ) ;
    return 0 ;
}


//*****************************************************************************
// 機能 : 指定のファイル名に一致する次のファイルを見つけて戻す。
//  入力 :  pfilepath = (見つかればここに、"x:\xxx\xxx\fff"形式で戻る)
//  戻り値: 0:OK , 1:ない , 2:エラー発生
//  注意 : GetTheFileFirstを事前に呼び、成功していること。
//*****************************************************************************
int GetTheFileNext( char* pfilepath )
{

    if ( !FindNextFile( hffind , &ffindt ) )
    {
        FileLastSx( ) ;
        return GetErrorCode( ) ;

    }

    for ( ; ; )
    {

        if ( g_pickupallfiles )
        {
            if ( !(ffindt.dwFileAttributes & (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_SYSTEM)) )
                break ;

        }
        else
        {
        
            if ( ffindt.dwFileAttributes & (FILE_ATTRIBUTE_NORMAL|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_ARCHIVE) )
                break ;

        }
    
        if ( !FindNextFile( hffind , &ffindt ) )
        {
            FileLastSx( ) ;
            return GetErrorCode( ) ;
        }
    }

    strcpy( pfilepath , ppathsave ) ;
    strcat( pfilepath , ffindt.cFileName ) ;
    return 0 ;
}


//*****************************************************************************
// 機能 : hffindの解放
//*****************************************************************************
void FileLastSx( )
{
    FindClose( hffind ) ;
}

 
//*****************************************************************************
// 機能 :指定のパスをチェックして、最後についている\の位置を戻す。
//  注意  :\がない場合には、 -1 が戻る!!!
//*****************************************************************************
int GetLastYenPos( BYTE* buf , int blen )
{
    int pos = -1 ;          // 初期値!!!

    int i ;
    for ( i = 0 ; i < blen ; i++ )
    {
        if ( _ismbblead( buf[i] ) )
        {
            i++ ;
            continue ;

        }

        if ( buf[i] == '\\' )
            pos = i ;

    }

    return pos ;

}


//*****************************************************************************
// 機能 :単に 1 で戻すだけ
//  注意 :for debug
//*****************************************************************************
int GetErrorCode( )
{
    DWORD errord = GetLastError( ) ;
    return 1 ;

}

//*****************************************************************************
// ListUpFiles.cpp : Ver1.00  2006/12/26
// Example : int count = ListUpFiles( "d:\\wk\\wk_temp\\*.* d:\\wka\\*.txt" , pc , 1024*500 ) ;
//
// Copyright(C) Edcom Inc. (http://www.edcom.jp/) All rights reserved. 
//*****************************************************************************