diff options
author | Björn Gustavsson <[email protected]> | 2017-09-14 12:52:02 +0200 |
---|---|---|
committer | Björn Gustavsson <[email protected]> | 2017-10-04 11:37:43 +0200 |
commit | 36dc96339e2b2b692e6dfe6de43db3a2348732bd (patch) | |
tree | ef62a03b52cc627de29fb5ad7250984c0a8a41f9 /lib/stdlib/src | |
parent | 49d0857634fc1a990ab97a144787288570fa2507 (diff) | |
download | otp-36dc96339e2b2b692e6dfe6de43db3a2348732bd.tar.gz otp-36dc96339e2b2b692e6dfe6de43db3a2348732bd.tar.bz2 otp-36dc96339e2b2b692e6dfe6de43db3a2348732bd.zip |
Implement escaping of special characters in wildcards
Allow characters with special meaning to be escaped using
\ (which must be writen as \\ in a string). That allows
matching of filenames containing characters that are special
in wildcards.
This is an incompatible change, but note that the use of backslashes
in wildcards would already work differently on Windows and Unix. Take
for example this call:
filelib:wildcard("a\\b")
On Windows, filelib:wildcard/1 would look for a directory named
"a", and a file or directory named "b" inside it.
On Unix, filelib:wildcard/1 would look for a file named "a\\b".
With this commit applied, filelib:wildcard/1 will look for
a file named "ab" on both Windows and Unix.
https://bugs.erlang.org/browse/ERL-451
Diffstat (limited to 'lib/stdlib/src')
-rw-r--r-- | lib/stdlib/src/filelib.erl | 42 |
1 files changed, 40 insertions, 2 deletions
diff --git a/lib/stdlib/src/filelib.erl b/lib/stdlib/src/filelib.erl index d7c313f214..0f90b3fc33 100644 --- a/lib/stdlib/src/filelib.erl +++ b/lib/stdlib/src/filelib.erl @@ -365,11 +365,18 @@ do_list_dir(Dir, Mod) -> eval_list_dir(Dir, Mod). %%% Compiling a wildcard. + +%% Define characters used for escaping a \. +-define(ESCAPE_PREFIX, $@). +-define(ESCAPE_CHARACTER, [?ESCAPE_PREFIX,$e]). +-define(ESCAPED_ESCAPE_PREFIX, [?ESCAPE_PREFIX,?ESCAPE_PREFIX]). + %% Only for debugging. compile_wildcard(Pattern) when is_list(Pattern) -> {compiled_wildcard,?HANDLE_ERROR(compile_wildcard(Pattern, "."))}. -compile_wildcard(Pattern, Cwd0) -> +compile_wildcard(Pattern0, Cwd0) -> + Pattern = convert_escapes(Pattern0), [Root|Rest] = filename:split(Pattern), case filename:pathtype(Root) of relative -> @@ -409,7 +416,8 @@ compile_join({cwd,Cwd}, File0) -> compile_join({root,PrefixLen,Root}, File) -> {root,PrefixLen,filename:join(Root, File)}. -compile_part(Part) -> +compile_part(Part0) -> + Part = wrap_escapes(Part0), compile_part(Part, false, []). compile_part_to_sep(Part) -> @@ -445,6 +453,8 @@ compile_part([${|Rest], Upto, Result) -> error -> compile_part(Rest, Upto, [${|Result]) end; +compile_part([{escaped,X}|Rest], Upto, Result) -> + compile_part(Rest, Upto, [X|Result]); compile_part([X|Rest], Upto, Result) -> compile_part(Rest, Upto, [X|Result]); compile_part([], _Upto, Result) -> @@ -461,6 +471,8 @@ compile_charset1([Lower, $-, Upper|Rest], Ordset) when Lower =< Upper -> compile_charset1(Rest, compile_range(Lower, Upper, Ordset)); compile_charset1([$]|Rest], Ordset) -> {ok, {one_of, gb_sets:from_ordset(Ordset)}, Rest}; +compile_charset1([{escaped,X}|Rest], Ordset) -> + compile_charset1(Rest, ordsets:add_element(X, Ordset)); compile_charset1([X|Rest], Ordset) -> compile_charset1(Rest, ordsets:add_element(X, Ordset)); compile_charset1([], _Ordset) -> @@ -486,6 +498,32 @@ compile_alt(Pattern, Result) -> error end. +%% Convert backslashes to an illegal Unicode character to +%% protect in from filename:split/1. + +convert_escapes([?ESCAPE_PREFIX|T]) -> + ?ESCAPED_ESCAPE_PREFIX ++ convert_escapes(T); +convert_escapes([$\\|T]) -> + ?ESCAPE_CHARACTER ++ convert_escapes(T); +convert_escapes([H|T]) -> + [H|convert_escapes(T)]; +convert_escapes([]) -> + []. + +%% Wrap each escape in a tuple to remove the special meaning for +%% the character that follows. + +wrap_escapes(?ESCAPED_ESCAPE_PREFIX ++ T) -> + [?ESCAPE_PREFIX|wrap_escapes(T)]; +wrap_escapes(?ESCAPE_CHARACTER ++ [C|T]) -> + [{escaped,C}|wrap_escapes(T)]; +wrap_escapes(?ESCAPE_CHARACTER) -> + []; +wrap_escapes([H|T]) -> + [H|wrap_escapes(T)]; +wrap_escapes([]) -> + []. + badpattern(Reason) -> error({badpattern,Reason}). |