ssh_sample_cli.erl

来自「OTP是开放电信平台的简称」· ERL 代码 · 共 333 行

ERL
333
字号
-module(ssh_sample_cli).%% api-export([listen/1, listen/2]).%% %% our shell function%% -export([start_our_shell/1]).%% our command functions-export([cli_prime/1, cli_primes/1, cli_gcd/2, cli_lcm/2,	 cli_factors/1, cli_exit/0, cli_rho/1, cli_help/0,	 cli_crash/0, cli_users/0, cli_self/0,	 cli_user/0, cli_host/0]).%% imports-import(lists, [reverse/1, reverse/2, seq/2, prefix/2]).-import(math, [sqrt/1]).listen(Port) ->    listen(Port, []).listen(Port, Options) ->    ssh_cli:listen(fun(U, H) -> start_our_shell(U, H) end, Port, Options).%% our_routinesour_routines() ->    [     {"crash", cli_crash,    "            crash the cli"},     {"exit", cli_exit,      "            exit application"},     {"factors", cli_factors,"<int>       prime factors of <int>"},     {"gcd", cli_gcd,        "<int> <int> greatest common divisor"},     {"help", cli_help,      "            help text"},     {"lcm", cli_lcm,        "<int> <int> least common multiplier"},     {"prime", cli_prime,    "<int>       check for primality"},     {"primes", cli_primes,  "<int>       print all primes up to <int>"},     {"rho", cli_rho,        "<int>       prime factors using rho's alg."},     {"who",  cli_users,     "            lists users"},     {"user", cli_user,      "            print name of user"},     {"host", cli_host,      "            print host addr"},     {"self", cli_self,      "            print my pid"}    ].%% (we could of course generate this from module_info() something like this)%% our_routines1() ->%%     {value, {exports, Exports}} =%% 	lists:keysearch(exports, 1, module_info()),%%     get_cli(Exports, []).%% our_args1(N) -> our_args1(N, "").%% our_args1(0, S) -> S;%% our_args1(N, S) -> our_args1(N-1, S ++ "<int> ").%% get_cli([], Acc) ->%%     lists:sort(Acc);%% get_cli([{A, Arity} | Rest], Acc) ->%%     L = atom_to_list(A),%%     case lists:prefix("cli_", L) of%% 	true -> get_cli(Rest, [{tl4(L), A, our_args1(Arity)} | Acc]);%% 	false -> get_cli(Rest, Acc)%%     end.%% the longest common prefix of two stringscommon_prefix([C | R1], [C | R2], Acc) ->    common_prefix(R1, R2, [C | Acc]);common_prefix(_, _, Acc) ->    reverse(Acc).%% longest prefix in a list, given a prefixlongest_prefix(List, Prefix) ->    case [A || {A, _, _} <- List, prefix(Prefix, A)] of	[] ->	    {none, List};	[S | Rest] ->	    NewPrefix0 =		lists:foldl(fun(A, P) ->				    common_prefix(A, P, [])			    end, S, Rest),	    NewPrefix = nthtail(length(Prefix), NewPrefix0),	    {prefix, NewPrefix, [S | Rest]}    end.			%%% our expand function (called when the user presses TAB)%%% input: a reversed list with the row to left of the cursor%%% output: {yes|no, Expansion, ListofPossibleMatches}%%% where the atom no yields a beep%%% Expansion is a string inserted at the cursor%%% List... is a list that will be printed%%% Here we beep on prefixes that don't match and when the command%%% filled inexpand([$  | _]) ->    {no, "", []};expand(RevBefore) ->        Before = reverse(RevBefore),    case longest_prefix(our_routines(), Before) of	{prefix, P, [_]} ->	    {yes, P ++ " ", []};	{prefix, "", M} ->	    {yes, "", M};	{prefix, P, _M} ->	    {yes, P, []};	{none, _M} ->	    {no, "", []}    end.%%% spawns out shell loop, we use plain io to input and output%%% over ssh (the group module is our group leader, and takes%%% care of sending input to the ssh_sample_cli server)start_our_shell(User, Peer) ->    spawn(fun() ->		  io:setopts([{expand_fun, fun(Bef) -> expand(Bef) end}]),		  io:format("Enter command\n"),		  put(user, User),		  put(peer_name, Peer),		  our_shell_loop()	  end).%%% an ordinary Read-Eval-Print-loopour_shell_loop() ->    % Read    Line = io:get_line({format, "CLI> ", []}),    % Eval    Result = eval_cli(Line),    % Print    io:format("---> ~p\n", [Result]),    case Result of	done -> exit(normal);	crash -> 1 / 0;	_ -> our_shell_loop()    end.%%% translate a command to a functioncommand_to_function(Command) ->    case lists:keysearch(Command, 1, our_routines()) of	{value, {_, Proc, _}} -> Proc;	false -> unknown_cli    end.%%% evaluate a command lineeval_cli(Line) ->    case string:tokens(Line, " \n") of	[] -> [];	[Command | ArgStrings] ->	    Proc = command_to_function(Command),	    case fix_args(ArgStrings) of		{ok, Args} ->		    case catch apply(?MODULE, Proc, Args) of			{'EXIT', Error} ->			    {error, Error}; % wrong_number_of_arguments};			Result ->			    Result		    end;		Error ->		    Error	    end    end.%%% make command arguments to integersfix_args(ArgStrings) ->    case catch [list_to_integer(A) || A <- ArgStrings] of	{'EXIT', _} ->	    {error, only_integer_arguments};	Args ->	    {ok, Args}    end.		     %%% the commands, check for reasonable arguments here toocli_prime(N) when N < 1000000000 ->    rho(N) == [N] andalso is_prime(N);cli_prime(N) when N < 10000 ->    is_prime(N).cli_primes(N) when N < 1000000 ->    primes(N).cli_gcd(A, B) when is_integer(A), is_integer(B) ->    gcd(A, B).cli_lcm(A, B) when is_integer(A), is_integer(B) ->    lcm(A, B).cli_factors(A) when A < 1000000 ->    factors(A).cli_user() ->    get(user).cli_host() ->    get(peer_name).cli_users() ->    case ssh_userauth:get_auth_users() of	{ok, UsersPids} ->	    UsersPids; % [U || {U, _} <- UsersPids];	E ->	    E    end.cli_self() ->    self().cli_crash() ->    crash.    cli_rho(A) ->    rho(A).cli_exit() ->    done.help_str(L) ->    help_str(L, []).help_str([], Acc) ->    lists:sort(Acc);help_str([{CommandName, _, HelpS} | Rest], Acc) ->    C = string:left(CommandName, 10),    help_str(Rest, [[C, " ", HelpS, $\n] | Acc]).cli_help() ->    HelpString = ["CLI Sample\n" | help_str(our_routines())],    io:format("~s\n", [HelpString]).%% a quite simple Sieve of Erastothenes (not tail-recursive, though)primes(Size) ->    era(sqrt(Size), seq(2,Size)).era(Max, [H|T]) when H =< Max ->    [H | era(Max, sieve([H|T], H))];era(_Max, L) ->     L.sieve([H|T], N) when H rem N =/= 0 ->    [H | sieve(T, N)];sieve([_H|T], N) ->    sieve(T, N);sieve([], _N) ->    [].%% another sieve, for getting the next prime incrementallynext_prime([], _) ->    2;next_prime([2], 2) ->    3;next_prime(Primes, P) ->    next_prime1(Primes, P).next_prime1(Primes, P) ->    P1 = P + 2,    case divides(Primes, trunc(sqrt(P1)), P1) of	false -> P1;	true -> next_prime1(Primes, P1)    end.divides([], _, _) ->    false;divides([A | _], Nsqrt, _) when A > Nsqrt ->    false;divides([A | _], _, N) when N rem A == 0 ->    true;divides([_ | R], Nsqrt, N) ->    divides(R, Nsqrt, N).is_prime(P) ->    lists:all(fun(A) -> P rem A =/= 0 end, primes(trunc(sqrt(P)))).%% Normal gcd, Euclidgcd(R, Q) when abs(Q) < abs(R) -> gcd1(Q,R);gcd(R, Q) -> gcd1(R,Q).gcd1(0, Q) -> Q;gcd1(R, Q) ->    gcd1(Q rem R, R).%% Least common multiple of (R,Q)lcm(0, _Q) -> 0;lcm(_R, 0) -> 0;lcm(R, Q) ->    (Q div gcd(R, Q)) * R.%%% Prime factors of a number (na飗e implementation)factors(N) ->    Nsqrt = trunc(sqrt(N)),    factors([], N, 2, Nsqrt, []).    factors(_Primes, N, Prime, Nsqrt, Factors) when Prime > Nsqrt ->    reverse(Factors, [N]);factors(Primes, N, Prime, Nsqrt, Factors) ->    case N rem Prime of	0 ->	    %%io:format("factor ------- ~p\n", [Prime]),	    N1 = N div Prime,	    factors(Primes, N1, Prime, trunc(sqrt(N1)), [Prime|Factors]);	_ ->	    Primes1 = Primes ++ [Prime],	    Prime1 = next_prime(Primes1, Prime),	    factors(Primes1, N, Prime1, Nsqrt, Factors)    end.%%% Prime factors using Rho's algorithm ("reminded" from wikipedia.org)%%% (should perhaps have used Brent instead, but it's not as readable)rho_pseudo(X, C, N) ->    (X * X + C) rem N.rho(N) when N > 1000 ->    case rho(2, 2, 1, N, fun(X) -> rho_pseudo(X, 1, N) end) of	failure ->	    [N];	F ->	    lists:sort(rho(F) ++ rho(N div F))    end;rho(N) ->    factors(N).rho(X, Y, 1, N, Pseudo) ->    X1 = Pseudo(X),    Y1 = Pseudo(Pseudo(Y)),    D = gcd(absdiff(X1, Y1), N),    rho(X1, Y1, D, N, Pseudo);rho(_X, _Y, D, N, _Pseudo) when 1 < D, D < N ->    D;rho(_X, _Y, D, N, _Pseudo) when D == N ->    failure.    absdiff(A, B) when A > B ->    A - B;absdiff(A, B) ->    B - A.%%% nthtail as in lists, but no badarg if n > the length of listnthtail(0, A) -> A;nthtail(N, [_ | A]) -> nthtail(N-1, A);nthtail(_, _) -> [].

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?