📄 xref_utils.erl
字号:
%% ``The contents of this file are subject to the Erlang Public License,%% Version 1.1, (the "License"); you may not use this file except in%% compliance with the License. You should have received a copy of the%% Erlang Public License along with this software. If not, it can be%% retrieved via the world wide web at http://www.erlang.org/.%% %% Software distributed under the License is distributed on an "AS IS"%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See%% the License for the specific language governing rights and limitations%% under the License.%% %% The Initial Developer of the Original Code is Ericsson Utvecklings AB.%% Portions created by Ericsson are Copyright 2000, Ericsson Utvecklings%% AB. All Rights Reserved.''%% %% $Id $%%-module(xref_utils).-export([xset/2]).-export([is_directory/1, file_info/1, fa_to_mfa/2]).-export([is_string/2, is_path/1]).-export([module_filename/2, application_filename/1, application_filename/2]).-export([release_directory/3, select_application_directories/2, filename_to_application/1, select_last_application_version/1, split_filename/2, scan_directory/4, list_path/2]).-export([predefined_functions/0, is_funfun/3, is_builtin/3]).-export([is_static_function/2]).-export([closure/1, components/1, condensation/1, path/2, use/2, call/2]).-export([regexpr/2]).-export([relation_to_graph/1]).-export([find_beam/1]).-export([options/2]).-export([subprocess/2]).-export([format_error/1]).-import(lists, [append/1, delete/2, filter/2, foldl/3, foreach/2, keydelete/3, keysearch/3, keysort/2, last/1, map/2, member/2, reverse/1, sort/1]).-import(sofs, [difference/2, domain/1, family/1, family_to_relation/1, from_external/2, from_term/2, intersection/2, partition/2, relation/1, relation_to_family/1, restriction/2, set/1, to_external/1, type/1]).-include_lib("kernel/include/file.hrl").%%%% Exported functions%%xset(L, T) when is_list(L) -> from_external(lists:usort(L), T);xset(S, T) -> from_external(S, T).%% -> true | false | {error, ?MODULE, Reason}%is_directory(F) ->% filelib:is_dir(F);is_directory(F) -> case file:read_file_info(F) of {ok, Info} -> Info#file_info.type =:= directory; {error, Error} -> file_error(F, Error) end.%% file_info(FileName) -> {ok, FileInfo} | {error, ?MODULE, Reason}%% FileInfo = {FileName, DirOrFile, Readable, ModificationTime}%% DirOrFile = directory | file%% Readable = readable | unreadable%% ModificationTime = {{Year, Month, Day}, {Hour, Minute, Second}}%%%% DirOrFile is equal to 'directory' ('file') if FileName is a%% directory (regular file).%% Readable is equal 'readable' ('unreadable') if FileName is readable%% (unreadable).%% ModificationTime is copied from file_info.mtime.%%file_info(F) -> case file:read_file_info(F) of {ok, Info} -> Readable = case Info#file_info.access of Access when Access =:= read; Access =:= read_write -> readable; _ -> unreadable end, Type = case Info#file_info.type of directory -> directory; regular -> file; _ -> error end, case Type of error -> error({unrecognized_file, F}); _ -> {ok, {F, Type, Readable, Info#file_info.mtime}} end; {error, Error} -> file_error(F, Error) end. fa_to_mfa(FAs, Mod) -> fa_to_mfa(FAs, Mod, []).fa_to_mfa([{F,A} | MFs], Mod, L) -> fa_to_mfa(MFs, Mod, [{Mod,F,A} | L]);fa_to_mfa([], _Mod, L) -> reverse(L).module_filename(Dir, Module) -> filename:join(Dir, to_list(Module) ++ code:objfile_extension()).application_filename(AppName) -> to_list(AppName) ++ ".app".application_filename(Dir, AppName) -> filename:join(to_list(Dir), application_filename(AppName)).%% -> bool()is_string([], _) -> false;is_string(Term, C) -> is_string1(Term, C).is_string1([H | T], C) when H > C, H < 127 -> is_string1(T, C);is_string1([], _) -> true;is_string1(_, _) -> false. %% -> bool()is_path([S | Ss]) -> case is_string(S, 31) of true -> is_path(Ss); false -> false end;is_path([]) -> true;is_path(_) -> false.%====================================% Release and application functions.%====================================%%% ApplDir = {ApplicationName,NumericApplicationVersion,ApplicationDirectory}%%% ApplicationName = atom()%%% ApplicationDirectory = string()%%% NumericApplicationVersion = [integer()] ("3.1.7" becomes [3,1,7]).%%% [] means that the application has no version...%%%%%% ModuleName = ModuleFileName = string()%%% ReleaseName = atom()%% release_directory(Directory, CheckLib, SubDirectory) -> %% {ok, ReleaseName, AppDir, [ApplDir]} | {error, ?MODULE, Reason}%% CheckLib = bool()%% AppDir = string()%% SubDirectory = string()%%%% Returns all sub directories of a given directory, assuming all sub%% directories are application directories. If a sub directory has a%% sub directory SubDirectory, that one is chosen as application%% directory. If Directory has a sub directory 'lib' and CheckLib is%% equal to 'true', applications are looked for on that%% directory. ApplDir is the directory where applications reside. In%% any case, the returned ReleaseName is the basename of the given%% directory.%%release_directory(Dir, UseLib, SubDir) -> SDir = subdir(Dir, "lib", UseLib), case file:list_dir(SDir) of {ok, FileNames} -> Files = [filename:join(SDir, File) || File <- FileNames], case select_application_directories(Files, SubDir) of {ok, ApplDirs} -> {ok, list_to_atom(filename:basename(Dir)), SDir, ApplDirs}; Error -> Error end; {error, Error} -> file_error(SDir, Error) end.%% select_application_directories([FileName], SubDirectory) -> %% {ok, [ApplDir]} | {error, ?MODULE, Error}%% SubDirectory = string()%%%% For each filename that is a directory, the filename is split into%% an application name and an application version, if possible, using%% '-' as separator. If not possible, the empty version - [] - is%% used. If a directory has a sub directory called SubDirectory, that%% one is returned as application directory rather than the directory%% itself.%% select_application_directories(FileNames, Dir) -> select_application_directories(FileNames, Dir, Dir =/= [], []).%% filename_to_application(FileName) -> %% {ApplicationName,NumbericApplicationVersion}%%%% Interprets a filename as an application name and an application%% version. If the filename (the basename actually) cannot be split%% into two components using '-' as separator, the whole basename is%% used as application name, and the version returned is [].%%filename_to_application(FileName) -> Basename = filename:basename(FileName), case catch filename2appl(Basename) of {'EXIT',_} -> {list_to_atom(Basename),[]}; Split -> Split end. %% select_last_application_version([ApplDir]) -> [ApplDir]%%%% For each application that occurs with more than one version in the%% input list, only the one with the last version is kept.%%select_last_application_version(AppVs) -> TL = to_external(partition(1, relation(AppVs))), [last(keysort(2, L)) || L <- TL].%% scan_directory(Directory, Recurse, Collect, Watch) -> %% {Collected, Errors, Seen, Unreadable}%%%% Watch = Collect = [string()]%% Directory = string() | atom()%% Recurse = bool()%% Collected = [{Dir,Basename}]%% Dir = Basename = Seen = Unreadable = [string()]%% %% Collected (Seen) contains those regular files with extension%% occurring in Collect (Watch). Watch is tried only if a filename%% does not match Collect. Only readable files occur in Collected, the%% unreadable files (with extension matching Collect) go into%% Unreadable.%%scan_directory(File, Recurse, Collect, Watch) -> Init = [[] | {[],[],[]}], [L | {E,J,U}] = find_files_dir(File, Recurse, Collect, Watch, Init), {reverse(L), reverse(E), reverse(J), reverse(U)}.%% {Dir, Basename} | falsesplit_filename(File, Extension) -> case catch begin Dir = filename:dirname(File), Basename = filename:basename(File, Extension), {Dir, Basename++Extension} end of {'EXIT', _} -> false; R -> R end.%% list_path(Path, Extensions) -> %% {[{Module, {integer(), Directory, Basename}}], [error()]}%%%% Path = [Directory]%% Extensions = [string()]%% Module = atom()%% Directory = Basename = string()%%%% Files with any of the given extensions are searched for among%% the given directories (Path). Directories "below" some of the given%% directories are not searched (unless enumerated in Path). If some%% file is found on more than one directory, the first one found is%% returned (Path is searched from the beginning).%%list_path(P, Extensions) -> list_dirs(P, 1, Extensions, [], []).list_dirs([D | Ds], I, Exts, CL, E) -> Fun = fun(X, A) -> File = filename:join(D, X), case is_directory(File) of false -> Ext = filename:extension(X), case member(Ext, Exts) of true -> M = list_to_atom(filename:basename(X, Ext)), [{M, {I,D,X}} | A]; false -> A end; true -> A; _Else -> A end end, {NCL, NE} = case file:list_dir(D) of {ok, C0} -> {foldl(Fun, CL, C0), E}; {error, Error} -> {CL, [file_error(D, Error) | E]} end, list_dirs(Ds, I+1, Exts, NCL, NE);list_dirs([], _I, _Exts, C, E) -> {C, E}.%% Returns functions that are present in all modules.predefined_functions() -> [{module_info,0}, {module_info,1}].%% Returns true if an MFA takes functional arguments.is_funfun(erlang, apply, 2) -> true;is_funfun(erlang, apply, 3) -> true;is_funfun(erlang, spawn, 1) -> true;is_funfun(erlang, spawn, 2) -> true;is_funfun(erlang, spawn, 3) -> true;is_funfun(erlang, spawn, 4) -> true;is_funfun(erlang, spawn_link, 1) -> true;is_funfun(erlang, spawn_link, 2) -> true;is_funfun(erlang, spawn_link, 3) -> true;is_funfun(erlang, spawn_link, 4) -> true;is_funfun(erlang, spawn_opt, 2) -> true;is_funfun(erlang, spawn_opt, 3) -> true;is_funfun(erlang, spawn_opt, 4) -> true;is_funfun(erlang, spawn_opt, 5) -> true;is_funfun(erts_debug, apply, 4) -> true;is_funfun(_, _, _) -> false.is_builtin(erts_debug, apply, 4) -> true;is_builtin(M, F, A) -> erlang:is_builtin(M, F, A).%% A "static function" is a function in an abstract module that may be%% called directly.is_static_function(module_info, 0) -> true;is_static_function(module_info, 1) -> true;is_static_function(new, _) -> true;is_static_function(_F, _A) ->
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -