diff options
Diffstat (limited to 'lib/stdlib')
-rw-r--r-- | lib/stdlib/doc/src/filelib.xml | 9 | ||||
-rw-r--r-- | lib/stdlib/src/filelib.erl | 36 | ||||
-rw-r--r-- | lib/stdlib/test/filelib_SUITE.erl | 57 |
3 files changed, 99 insertions, 3 deletions
diff --git a/lib/stdlib/doc/src/filelib.xml b/lib/stdlib/doc/src/filelib.xml index f3079c7337..cec20aee8e 100644 --- a/lib/stdlib/doc/src/filelib.xml +++ b/lib/stdlib/doc/src/filelib.xml @@ -150,6 +150,11 @@ <p>Matches any number of characters up to the end of the filename, the next dot, or the next slash.</p> </item> + <tag>**</tag> + <item> + <p>Two adjacent <c>*</c>'s used as a single pattern will + match all files and zero or more directories and subdirectories.</p> + </item> <tag>[Character1,Character2,...]</tag> <item> <p>Matches any of the characters listed. Two characters @@ -192,6 +197,10 @@ <c>src</c> or <c>include</c> directories, use:</p> <code type="none"> filelib:wildcard("lib/*/{src,include}/*.{erl,hrl}") </code> + <p>To find all <c>.erl</c> or <c>.hrl</c> files in any + subdirectory, use:</p> + <code type="none"> + filelib:wildcard("lib/**/*.{erl,hrl}") </code> </desc> </func> <func> diff --git a/lib/stdlib/src/filelib.erl b/lib/stdlib/src/filelib.erl index fa4f92617c..318f3b87b8 100644 --- a/lib/stdlib/src/filelib.erl +++ b/lib/stdlib/src/filelib.erl @@ -132,6 +132,8 @@ do_wildcard_comp({compiled_wildcard,{exists,File}}, Mod) -> {ok,_} -> [File]; _ -> [] end; +do_wildcard_comp({compiled_wildcard,[cwd,Base|Rest]}, Mod) -> + do_wildcard_1([Base], Rest, Mod); do_wildcard_comp({compiled_wildcard,[Base|Rest]}, Mod) -> do_wildcard_1([Base], Rest, Mod). @@ -143,7 +145,11 @@ do_wildcard_comp({compiled_wildcard,{exists,File}}, Cwd, Mod) -> {ok,_} -> [File]; _ -> [] end; -do_wildcard_comp({compiled_wildcard,[current|Rest]}, Cwd0, Mod) -> +do_wildcard_comp({compiled_wildcard,[cwd|Rest0]}, Cwd0, Mod) -> + case Rest0 of + [current|Rest] -> ok; + Rest -> ok + end, {Cwd,PrefixLen} = case filename:join([Cwd0]) of Bin when is_binary(Bin) -> {Bin,byte_size(Bin)+1}; Other -> {Other,length(Other)+1} @@ -295,6 +301,8 @@ do_wildcard_2([File|Rest], Pattern, Result, Mod) -> do_wildcard_2([], _, Result, _Mod) -> Result. +do_wildcard_3(Base, [[double_star]|Rest], Result, Mod) -> + lists:sort(do_double_star(current, [Base], Rest, Result, Mod, true)); do_wildcard_3(Base, [Pattern|Rest], Result, Mod) -> case do_list_dir(Base, Mod) of {ok, Files0} -> @@ -328,6 +336,8 @@ wildcard_5([question|Rest1], [_|Rest2]) -> wildcard_5(Rest1, Rest2); wildcard_5([accept], _) -> true; +wildcard_5([double_star], _) -> + true; wildcard_5([star|Rest], File) -> do_star(Rest, File); wildcard_5([{one_of, Ordset}|Rest], [C|File]) -> @@ -348,6 +358,21 @@ wildcard_5([], [_|_]) -> wildcard_5([_|_], []) -> false. +do_double_star(Base, [H|T], Rest, Result, Mod, Root) -> + Full = join(Base, H), + Result1 = case do_list_dir(Full, Mod) of + {ok, Files} -> + do_double_star(Full, Files, Rest, Result, Mod, false); + _ -> Result + end, + Result2 = case Root andalso Rest == [] of + true -> Result1; + false -> do_wildcard_3(Full, Rest, Result1, Mod) + end, + do_double_star(Base, T, Rest, Result2, Mod, Root); +do_double_star(_Base, [], _Rest, Result, _Mod, _Root) -> + Result. + do_star(Pattern, [X|Rest]) -> case wildcard_5(Pattern, [X|Rest]) of true -> true; @@ -383,7 +408,10 @@ compile_wildcard_1(Pattern) -> [Root|Rest] = filename:split(Pattern), case filename:pathtype(Root) of relative -> - compile_wildcard_2([Root|Rest], current); + case compile_wildcard_2([Root|Rest], current) of + {exists,_}=Wc -> Wc; + [_|_]=Wc -> [cwd|Wc] + end; _ -> compile_wildcard_2(Rest, [Root]) end. @@ -416,6 +444,10 @@ compile_part([$}|Rest], true, Result) -> {ok, $}, lists:reverse(Result), Rest}; compile_part([$?|Rest], Upto, Result) -> compile_part(Rest, Upto, [question|Result]); +compile_part([$*,$*], Upto, Result) -> + compile_part([], Upto, [double_star|Result]); +compile_part([$*,$*|Rest], Upto, Result) -> + compile_part(Rest, Upto, [star|Result]); compile_part([$*], Upto, Result) -> compile_part([], Upto, [accept|Result]); compile_part([$*|Rest], Upto, Result) -> diff --git a/lib/stdlib/test/filelib_SUITE.erl b/lib/stdlib/test/filelib_SUITE.erl index 1de639a166..1fd7518519 100644 --- a/lib/stdlib/test/filelib_SUITE.erl +++ b/lib/stdlib/test/filelib_SUITE.erl @@ -176,9 +176,64 @@ do_wildcard_5(Dir, Wcf) -> %% Cleanup ?line del(Files), - ?line foreach(fun(D) -> ok = file:del_dir(filename:join(Dir, D)) end, Dirs). + ?line foreach(fun(D) -> ok = file:del_dir(filename:join(Dir, D)) end, Dirs), + do_wildcard_6(Dir, Wcf). + +do_wildcard_6(Dir, Wcf) -> + ok = file:make_dir(filename:join(Dir, "xbin")), + All = ["xbin/a.x","xbin/b.x","xbin/c.x"], + Files = mkfiles(All, Dir), + All = Wcf("xbin/*.x"), + All = Wcf("xbin/*"), + ["xbin"] = Wcf("*"), + All = Wcf("*/*"), + del(Files), + ok = file:del_dir(filename:join(Dir, "xbin")), + do_wildcard_7(Dir, Wcf). + +do_wildcard_7(Dir, Wcf) -> + Dirs = ["blurf","xa","yyy"], + SubDirs = ["blurf/nisse"], + foreach(fun(D) -> + ok = file:make_dir(filename:join(Dir, D)) + end, Dirs ++ SubDirs), + All = ["blurf/nisse/baz","xa/arne","xa/kalle","yyy/arne"], + Files = mkfiles(lists:reverse(All), Dir), + %% Test. + Listing = Wcf("**"), + ["blurf","blurf/nisse","blurf/nisse/baz", + "xa","xa/arne","xa/kalle","yyy","yyy/arne"] = Listing, + Listing = Wcf("**/*"), + ["xa/arne","yyy/arne"] = Wcf("**/arne"), + ["blurf/nisse"] = Wcf("**/nisse"), + [] = Wcf("mountain/**"), + + %% Cleanup + del(Files), + foreach(fun(D) -> + ok = file:del_dir(filename:join(Dir, D)) + end, SubDirs ++ Dirs), + do_wildcard_8(Dir, Wcf). + +do_wildcard_8(Dir, Wcf) -> + Dirs0 = ["blurf"], + Dirs1 = ["blurf/nisse"], + Dirs2 = ["blurf/nisse/a", "blurf/nisse/b"], + foreach(fun(D) -> + ok = file:make_dir(filename:join(Dir, D)) + end, Dirs0 ++ Dirs1 ++ Dirs2), + All = ["blurf/nisse/a/1.txt", "blurf/nisse/b/2.txt", "blurf/nisse/b/3.txt"], + Files = mkfiles(lists:reverse(All), Dir), + %% Test. + All = Wcf("**/blurf/**/*.txt"), + + %% Cleanup + del(Files), + foreach(fun(D) -> + ok = file:del_dir(filename:join(Dir, D)) + end, Dirs2 ++ Dirs1 ++ Dirs0). fold_files(Config) when is_list(Config) -> ?line Dir = filename:join(?config(priv_dir, Config), "fold_files"), |