shell.erl
来自「OTP是开放电信平台的简称」· ERL 代码 · 共 1,268 行 · 第 1/3 页
ERL
1,268 行
false -> exit({{bad_module_name, Mod}, [{shell,import,1}]}) end end;local_func(import_all, [P], Bs0, _Shell, _RT, _Lf, _Ef) -> case erl_parse:package_segments(P) of error -> exit({function_clause,[{shell,import_all,1}]}); P1 -> Name = packages:concat(P1), case packages:is_valid(Name) of true -> Bs1 = import_all(Name, Bs0), {value,ok,Bs1}; false -> exit({{bad_package_name, Name}, [{shell,import_all,1}]}) end end;local_func(use, [M], Bs, Shell, RT, Lf, Ef) -> local_func(import, [M], Bs, Shell, RT, Lf, Ef);local_func(use_all, [M], Bs, Shell, RT, Lf, Ef) -> local_func(import_all, [M], Bs, Shell, RT, Lf, Ef);local_func(history, [{integer,_,N}], Bs, _Shell, _RT, _Lf, _Ef) -> {value,history(N),Bs};local_func(history, [_Other], _Bs, _Shell, _RT, _Lf, _Ef) -> exit({function_clause,{shell,history,1}});local_func(results, [{integer,_,N}], Bs, _Shell, _RT, _Lf, _Ef) -> {value,results(N),Bs};local_func(results, [_Other], _Bs, _Shell, _RT, _Lf, _Ef) -> exit({function_clause,[{shell,results,1}]});local_func(exit, [], _Bs, Shell, _RT, _Lf, _Ef) -> shell_req(Shell, exit), %This terminates us exit(normal);local_func(F, As0, Bs0, _Shell, _RT, Lf, Ef) when is_atom(F) -> {As,Bs} = expr_list(As0, Bs0, Lf, Ef), non_builtin_local_func(F,As,Bs).non_builtin_local_func(F,As,Bs) -> case erlang:function_exported(user_default, F, length(As)) of true -> {eval,{user_default,F},As,Bs}; false -> {eval,{shell_default,F},As,Bs} end. local_func_handler(Shell, RT, Ef) -> H = fun(Lf) -> fun(F, As, Bs) -> local_func(F, As, Bs, Shell, RT, {eval,Lf(Lf)}, Ef) end end, {eval,H(H)}.record_print_fun(RT) -> fun(Tag, NoFields) -> case ets:lookup(RT, Tag) of [{_,{attribute,_,record,{Tag,Fields}}}] when length(Fields) =:= NoFields -> record_fields(Fields); _ -> no end end.record_fields([{record_field,_,{atom,_,Field}} | Fs]) -> [Field | record_fields(Fs)];record_fields([{record_field,_,{atom,_,Field},_} | Fs]) -> [Field | record_fields(Fs)];record_fields([]) -> [].initiate_records(Bs, RT) -> RNs1 = init_rec(shell_default, Bs, RT), RNs2 = case code:is_loaded(user_default) of {file,_File} -> init_rec(user_default, Bs, RT); false -> [] end, lists:usort(RNs1 ++ RNs2).init_rec(Module, Bs, RT) -> case read_records(Module, []) of RAs when is_list(RAs) -> case catch add_records(RAs, Bs, RT) of {'EXIT',_} -> []; RNs -> RNs end; _Error -> [] end.read_and_add_records(File, Selected, Options, Bs, RT) -> case read_records(File, Selected, Options) of RAs when is_list(RAs) -> add_records(RAs, Bs, RT); Error -> Error end.read_records(File, Selected, Options) -> case read_records(File, listify(Options)) of Error when is_tuple(Error) -> Error; RAs when Selected =:= '_' -> RAs; RAs -> Sel = listify(Selected), [RA || {attribute,_,_,{Name,_}}=RA <- RAs, lists:member(Name, Sel)] end.add_records(RAs, Bs0, RT) -> Recs = [{Name,D} || {attribute,_,_,{Name,_}}=D <- RAs], Bs1 = record_bindings(Recs, Bs0), case check_command([], Bs1) of {error,{_Line,M,ErrDesc}} -> %% A source file that has not been compiled. ErrStr = io_lib:fwrite("~s", [M:format_error(ErrDesc)]), exit(lists:flatten(ErrStr)); ok -> true = ets:insert(RT, Recs), lists:usort([Name || {Name,_} <- Recs]) end.listify(L) when is_list(L) -> L;listify(E) -> [E].check_command(Es, Bs) -> erl_eval:check_command(Es, strip_bindings(Bs)).expr(E, Bs, Lf, Ef) -> erl_eval:expr(E, strip_bindings(Bs), Lf, Ef).expr_list(Es, Bs, Lf, Ef) -> erl_eval:expr_list(Es, strip_bindings(Bs), Lf, Ef).strip_bindings(Bs) -> Bs -- [B || {{module,_},_}=B <- Bs].%% Note that a sequence number is used here to make sure that if a%% record is used by another record, then the first record is parsed%% before the second record. (erl_eval:check_command() calls the%% linter which needs the records in a proper order.)record_bindings([], Bs) -> Bs;record_bindings(Recs0, Bs0) -> {Recs1, _} = lists:mapfoldl(fun ({Name,Def}, I) -> {{Name,I,Def},I+1} end, 0, Recs0), Recs2 = lists:keysort(2, lists:ukeysort(1, Recs1)), Bs1 = lists:foldl(fun ({Name,I,Def}, Bs) -> erl_eval:add_binding({record,I,Name}, Def, Bs) end, Bs0, Recs2), Bs1.%%% Read record information from file(s)read_records(FileOrModule, Opts0) -> Opts = lists:delete(report_warnings, Opts0), case find_file(FileOrModule) of {files,[File]} -> read_file_records(File, Opts); {files,Files} -> lists:flatmap(fun(File) -> case read_file_records(File, Opts) of RAs when is_list(RAs) -> RAs; _ -> [] end end, Files); Error -> Error end.-include_lib("kernel/include/file.hrl").find_file(Mod) when is_atom(Mod) -> case code:which(Mod) of File when is_list(File) -> {files,[File]}; preloaded -> {_M,_Bin,File} = code:get_object_code(Mod), {files,[File]}; _Else -> % non_existing, interpreted, cover_compiled {error,nofile} end;find_file(File) -> case catch filelib:wildcard(File) of {'EXIT',_} -> {error,invalid_filename}; Files -> {files,Files} end.read_file_records(File, Opts) -> case filename:extension(File) of ".beam" -> case beam_lib:chunks(File, [abstract_code,"CInf"]) of {ok,{_Mod,[{abstract_code,{Version,Forms}},{"CInf",CB}]}} -> case record_attrs(Forms) of [] when Version =:= raw_abstract_v1 -> []; [] -> %% If the version is raw_X, then this test %% is unnecessary. try_source(File, CB); Records -> Records end; {ok,{_Mod,[{abstract_code,no_abstract_code},{"CInf",CB}]}} -> try_source(File, CB); Error -> %% Could be that the "Abst" chunk is missing (pre R6). Error end; _ -> parse_file(File, Opts) end.%% This is how the debugger searches for source files. See int.erl.try_source(Beam, CB) -> Os = case lists:keysearch(options, 1, binary_to_term(CB)) of false -> []; {value,{_,Os0}} -> Os0 end, Src0 = filename:rootname(Beam) ++ ".erl", case is_file(Src0) of true -> parse_file(Src0, Os); false -> EbinDir = filename:dirname(Beam), Src = filename:join([filename:dirname(EbinDir), "src", filename:basename(Src0)]), case is_file(Src) of true -> parse_file(Src, Os); false -> {error, nofile} end end.is_file(Name) -> case filelib:is_file(Name) of true -> not filelib:is_dir(Name); false -> false end.parse_file(File, Opts) -> Cwd = ".", Dir = filename:dirname(File), IncludePath = [Cwd,Dir|inc_paths(Opts)], case epp:parse_file(File, IncludePath, pre_defs(Opts)) of {ok,Forms} -> record_attrs(Forms); Error -> Error end.pre_defs([{d,M,V}|Opts]) -> [{M,V}|pre_defs(Opts)];pre_defs([{d,M}|Opts]) -> [M|pre_defs(Opts)];pre_defs([_|Opts]) -> pre_defs(Opts);pre_defs([]) -> [].inc_paths(Opts) -> [P || {i,P} <- Opts, is_list(P)].record_attrs(Forms) -> [A || A = {attribute,_,record,_D} <- Forms].%%% End of reading record information from file(s)import_all(P, Bs0) -> Ms = packages:find_modules(P), lists:foldl(fun (M, Bs) -> Key = list_to_atom(M), M1 = list_to_atom(packages:concat(P, M)), erl_eval:add_binding({module,Key}, M1, Bs) end, Bs0, Ms).shell_req(Shell, Req) -> Shell ! {shell_req,self(),Req}, receive {shell_rep,Shell,Rep} -> Rep end.list_commands([{{N,command},Es0}, {{N,result}, V} |Ds], RT) -> Es = prep_list_commands(Es0), VS = io_lib_pretty:print(V, 4, 80, ?LINEMAX, record_print_fun(RT)), Ns = io_lib:fwrite("~w: ", [N]), I = iolist_size(Ns), io:requests([{put_chars, Ns}, {format,"~s~n",[erl_pp:exprs(Es, I, none)]}, {format,"-> ",[]}, {put_chars, VS}, nl]), list_commands(Ds, RT);list_commands([{{N,command},Es0} |Ds], RT) -> Es = prep_list_commands(Es0), Ns = io_lib:fwrite("~w: ", [N]), I = iolist_size(Ns), io:requests([{put_chars, Ns}, {format,"~s~n",[erl_pp:exprs(Es, I, none)]}]), list_commands(Ds, RT);list_commands([_D|Ds], RT) -> list_commands(Ds, RT);list_commands([], _RT) -> ok.list_bindings([{{module,M},Val}|Bs], RT) -> io:fwrite("~p is ~p~n", [M,Val]), list_bindings(Bs, RT);list_bindings([{Name,Val}|Bs], RT) -> case erl_eval:fun_data(Val) of {fun_data,_FBs,FCs0} -> FCs = expand_value(FCs0), % looks nicer F = {'fun',0,{clauses,FCs}}, M = {match,0,{var,0,Name},F}, io:fwrite("~s~n", [erl_pp:expr(M)]); false -> Namel = io_lib:fwrite("~s = ", [Name]), Nl = iolist_size(Namel)+1, io:put_chars(Namel), ValS = io_lib_pretty:print(Val, Nl, 80, ?LINEMAX, record_print_fun(RT)), io:put_chars(ValS), io:nl() end, list_bindings(Bs, RT);list_bindings([], _RT) -> ok.list_records(Records) -> lists:foreach(fun({_Name,Attr}) -> io:fwrite("~s", [erl_pp:attribute(Attr)]) end, Records).record_defs(RT, Names) -> lists:flatmap(fun(Name) -> ets:lookup(RT, Name) end, Names).expand_value(E) -> substitute_v1(fun({value,CommandN,V}) -> try_abstract(V, CommandN) end, E).%% There is no abstract representation of funs.try_abstract(V, CommandN) -> try erl_parse:abstract(V) catch _:_ -> {call,0,{atom,0,v},[{integer,0,CommandN}]} end.%% Rather than listing possibly huge results the calls to v/1 are shown.prep_list_commands(E) -> substitute_v1(fun({value,CommandN,_V}) -> {call,0,{atom,0,v},[{integer,0,CommandN}]} end, E).substitute_v1(F, {value,_,_}=Value) -> F(Value);substitute_v1(F, T) when is_tuple(T) -> list_to_tuple(substitute_v1(F, tuple_to_list(T)));substitute_v1(F, [E | Es]) -> [substitute_v1(F, E) | substitute_v1(F, Es)];substitute_v1(_F, E) -> E.check_and_get_history_and_results() -> check_env(shell_history_length, "shell history length"), check_env(shell_saved_results, "max number of saved results"), get_history_and_results().get_history_and_results() -> History = get_env(shell_history_length, ?DEF_HISTORY), Results = get_env(shell_saved_results, ?DEF_RESULTS), {History, min(Results, History)}.min(X, Y) when X < Y -> X;min(_X, Y) -> Y.get_env(V, Def) -> case application:get_env(stdlib, V) of {ok, Val} when is_integer(Val), Val >= 0 -> Val; _ -> Def end. check_env(V, Name) -> case application:get_env(stdlib, V) of undefined -> ok; {ok, Val} when is_integer(Val), Val >= 0 -> ok; {ok, Val} -> Txt = io_lib:fwrite("Invalid ~s ~p~n", [Name, Val]), error_logger:info_report(lists:flatten(Txt)) end. set_env(App, Name, Val, Default) -> Prev = case application:get_env(App, Name) of undefined -> Default; {ok, Old} -> Old end, application_controller:set_env(App, Name, Val), Prev.history(L) when is_integer(L), L >= 0 -> set_env(stdlib, shell_history_length, L, ?DEF_HISTORY).results(L) when is_integer(L), L >= 0 -> set_env(stdlib, shell_saved_results, L, ?DEF_RESULTS).
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?