123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
/*******************************************************************************

        copyright:      Copyright (c) 2004 Kris Bell. All rights reserved

        license:        BSD style: $(LICENSE)

        version:        Jun 2004: Initial release
        version:        Dec 2006: Pacific release

        author:         Kris

*******************************************************************************/

module tango.io.FileScan;



public  import tango.io.FilePath;

private import tango.core.Exception;

pragma(msg, "tango.io.FileScan is deprecated. Please use tango.io.FilePath.toList or tango.io.vfs.* instead.");

deprecated:

/*******************************************************************************
    This module is deprecated because it doesn't support file globbing
    or regexes for matching files and because it ignores folders that
    it doesn't recurse into (a non-recursive scan will never return any
    folders).

        Recursively scan files and directories, adding filtered files to
        an output structure as we go. This can be used to produce a list
        of subdirectories and the files contained therein. The following
        example lists all files with suffix ".d" located via the current
        directory, along with the folders containing them:
        ---
        auto scan = new FileScan;

        scan (".", ".d");

        Stdout.formatln ("{} Folders", scan.folders.length);
        foreach (folder; scan.folders)
                 Stdout.formatln ("{}", folder);

        Stdout.formatln ("\n{} Files", scan.files.length);
        foreach (file; scan.files)
                 Stdout.formatln ("{}", file);
        ---

        This is unlikely the most efficient method to scan a vast number of
        files, but operates in a convenient manner.

*******************************************************************************/

class FileScan
{
        alias sweep     opCall;

        FilePath[]      fileSet;
        const(char)[][]        errorSet;
        FilePath[]      folderSet;
        
        /***********************************************************************

            Alias for Filter delegate. Accepts a FilePath & a bool as
            arguments and returns a bool.

            The FilePath argument represents a file found by the scan,
            and the bool whether the FilePath represents a folder.

            The filter should return true, if matched by the filter. Note
            that returning false where the path is a folder will result
            in all files contained being ignored. To always recurse folders,
            do something like this:
            ---
            return (isDir || match (fp.name));
            ---

        ***********************************************************************/

        alias FilePath.Filter Filter;

       /***********************************************************************

                Return all the errors found in the last scan

        ***********************************************************************/

        public const(char)[][] errors ()
        {
                return errorSet;
        }

        /***********************************************************************

                Return all the files found in the last scan

        ***********************************************************************/

        public FilePath[] files ()
        {
                return fileSet;
        }

        /***********************************************************************
        
                Return all directories found in the last scan

        ***********************************************************************/

        public FilePath[] folders ()
        {
                return folderSet;
        }

        /***********************************************************************

                Sweep a set of files and directories from the given parent
                path, with no filtering applied
        
        ***********************************************************************/
        
        FileScan sweep (const(char)[] path, bool recurse=true)
        {
                return sweep (path, cast(Filter) null, recurse);
        }

        /***********************************************************************

                Sweep a set of files and directories from the given parent
                path, where the files are filtered by the given suffix
        
        ***********************************************************************/
        
        FileScan sweep (const(char)[] path, const(char)[] match, bool recurse=true)
        {
                return sweep (path, (FilePath fp, bool isDir)
                             {return isDir || fp.suffix == match;}, recurse);
        }

        /***********************************************************************

                Sweep a set of files and directories from the given parent
                path, where the files are filtered by the provided delegate

        ***********************************************************************/
        
        FileScan sweep (const(char)[] path, Filter filter, bool recurse=true)
        {
                errorSet = null, fileSet = folderSet = null;
                /* Bad dup */
                return scan (new FilePath(path.dup), filter, recurse);
        }

        /***********************************************************************

                Internal routine to locate files and sub-directories. We
                skip entries with names composed only of '.' characters. 

        ***********************************************************************/

        private FileScan scan (FilePath folder, Filter filter, bool recurse) 
        {
                try {
                    auto paths = folder.toList (filter);

                    auto count = fileSet.length;
                    foreach (path; paths)
                             if (! path.isFolder)
                                   fileSet ~= path;
                             else
                                if (recurse)
                                    scan (path, filter, recurse);

                    // add packages only if there's something in them
                    if (fileSet.length > count)
                        folderSet ~= folder;

                    } catch (IOException e)
                             errorSet ~= e.toString();
                return this;
        }
}


/*******************************************************************************

*******************************************************************************/

debug (FileScan)
{
        import tango.io.Stdout;

        void main()
        {
                auto scan = new FileScan;

                scan (".");

                Stdout.formatln ("{} Folders", scan.folders.length);
                foreach (folder; scan.folders)
                         Stdout (folder).newline;

                Stdout.formatln ("\n{} Files", scan.files.length);
                foreach (file; scan.files)
                         Stdout (file).newline;

                Stdout.formatln ("\n{} Errors", scan.errors.length);
                foreach (error; scan.errors)
                         Stdout (error).newline;
        }
}