1 module find;
2 
3 import std.file;
4 import std.path;
5 import std.range;
6 import std.regex;
7 import std.stdio;
8 import std.algorithm;
9 
10 import core.exception;
11 
12 import commando;
13 
14 void main( string[] args )
15 {
16 	// Declare the variables for the arguments
17 	bool recurse;
18 	bool isRegex;
19 	string directory;
20 	string pattern;
21 
22 	try
23 	{
24 		// the `parse` method takes a string array and a delegate.
25 		// The delegate will be used for building the parser
26 		ArgumentParser.parse( args, ( ArgumentSyntax syntax )
27 		{
28 			// we use `commando.CaseSensitive.yes` here because CaseSensitive conflicts with the std lib
29 			syntax.config.caseSensitive = commando.CaseSensitive.yes;
30 
31 			// Define our options with the `option` method.
32 			// The `option` method has the following signature: `void option( T )( char shortName, string longName, T* ptr, Required required, string helpText )`
33 			syntax.option( 'r', "recurse", &recurse, Required.no, "Search directory recursively" );
34 			syntax.option( 'R', "regex", &isRegex, Required.no, "Specify that the pattern is a regular expression (defult is glob)" );
35 			syntax.option( 'p', "pattern", &pattern, Required.yes, "The file name search pattern" );
36 			syntax.option( 'd', "directory", &directory, Required.yes, "The directory to search" );
37 		} );
38 	}
39 	catch( ArgumentParserException ex )
40 	{
41 		// Catch any exceptions while building the parser or actually parsing and display it nicely.
42 		stderr.writefln( ex.msg );
43 		return;
44 	}
45 
46 	bool filterFiles( string name )
47 	{
48 		if( !name.exists )
49 			return false;
50 
51 		if( name.isDir )
52 			return false;
53 
54 		try
55 		{
56 			return isRegex ? !!name.matchFirst( pattern ) : name.globMatch( pattern );
57 		}
58 		catch( RegexException ex )
59 		{
60 			stderr.writefln( "Error in regular expression: %s", ex.msg );
61 			assert( false );
62 		}
63 	}
64 
65 	string normalize( string path )
66 	{
67 		return path.asNormalizedPath
68 	               .array
69 				   .asAbsolutePath
70 				   .array
71 				   .idup;
72 	}
73 
74 	if( !directory.isValidPath )
75 	{
76 		stderr.writefln( "'%s' is not a valid path" );
77 		return;
78 	}
79 
80 	try
81 	{
82 		directory = normalize( directory );
83 		auto entries = directory.dirEntries( SpanMode.breadth )
84 								.filter!( filterFiles )
85 								.map!( normalize );
86 
87 		foreach( entry; entries )
88 			writeln( entry );
89 	}
90 	catch( AssertError ) { }
91 	catch( Throwable th )
92 	{
93 		stderr.writefln( "Error while searching for files: %s", th.msg );
94 	}
95 }