Current section
Files
Jump to
Current section
Files
src/lfe_init_new_1.erl
%% Copyright (c) 2008-2024 Robert Virding
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
%% You may obtain a copy of the License at
%%
%% http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing, software
%% distributed under the License is distributed on an "AS IS" BASIS,
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions and
%% limitations under the License.
%%% File : lfe_init.erl
%%% Author : Robert Virding
%%% Purpose : Lisp Flavoured Erlang init module.
%%% This little beauty allows you to start Erlang with the LFE shell
%%% running and still has ^G and user_drv enabled. Use it as follows:
%%%
%%% erl -user lfe_init
%%%
%%% Add -pa to find modules if necessary.
%%%
%%% Thanks to Attila Babo for showing me how to do this.
%%% The calls needed to start user/user_drv have changed from OTP
%%% 26. In the release after 26 the module user no longer exists and
%%% user_drv has a different interface. Note that this is sort of
%%% documented but these modules are not included in the standard
%%% Erlang documentation.
-module(lfe_init_new_1).
-export([start/0]).
-export([do_eval/1,do_script/1]).
-include("lfe.hrl").
%% Exit status.
-define(OK_STATUS, 0).
-define(ERROR_STATUS, 127).
%% Default repl to use when none is given.
-define(DEFAULT_REPL, lfe_repl).
%% Start LFE running a script or the shell depending on arguments.
start() ->
erlang:display(init:get_arguments()),
erlang:display(init:get_plain_arguments()),
OTPRelease = erlang:system_info(otp_release),
%% Find out which repl/shell we want to use.
Repl = case init:get_argument(repl) of
{ok, [[R|_]]} -> list_to_atom(R);
_Other -> ?DEFAULT_REPL
end,
%% Get the LFE evals to be done.
Evals = case init:get_argument('lfe-eval') of
{ok, Es} -> lists:append(Es);
error -> []
end,
%% Check whether we are to start the repl or run a terminating
%% script file.
case init:get_argument('run-script') of
error -> %No script file to run
if OTPRelease >= "26" ->
%% The new way 26 and later.
user_drv:start(#{initial_shell => {Repl,start,[]}});
true ->
%% The old way before 26.
user_drv:start(['tty_sl -c -e',{Repl,start,[]}])
end,
do_eval(Evals);
{ok, [Script | _]} -> %There is a script file
if OTPRelease >= "26" ->
%% The new way 26 and later)
user_drv:start(#{initial_shell => noshell});
true ->
%% The old way before 26.
user:start()
end,
do_eval_script(Evals, Script, Repl)
end.
%% Tools to run at initialisation.
%% do_eval(EvalStrings) -> ok.
%% Parse and evaluate the strings.
do_eval(Evals) ->
foreach(fun run_eval/1, Evals).
do_script(Script) ->
lfescript_new:start(Script).
%% do_eval_script(Evals, Script, Repl) -> Pid.
%% Run the script after which LFE is terminated.
do_eval_script(Evals, Script, Repl) ->
Run = fun () ->
%% io:format(user, "es ~p\n", [{Evals,Script}]),
%% St = Repl:run_strings(Evals),
do_eval(Evals),
do_script(Script)
end,
spawn_link(fun () -> run_script(Repl, Run) end).
%% run_eval(EvalString) -> Value.
run_eval(Eval) ->
case lfe_io:read_string(Eval) of
{ok,Exprs} ->
lfe_eval:exprs(Exprs);
{error, E} ->
error(E)
end.
%% run_script(Repl, Run)
%% Run a script and terminate the erlang process afterwards.
run_script(Repl, Run) ->
try
Run(), %Evaluate the evals and script
%% For some reason we need to wait a bit before stopping.
timer:sleep(1),
init:stop(?OK_STATUS)
catch
?CATCH(Class, Error, Stack)
Skip = fun (M, _F, _A) ->
(M =:= lfe_eval) or (M =:= Repl) or (M =:= ?MODULE)
end,
Format = fun (T, I) -> lfe_io:prettyprint1(T, 15, I, 80) end,
Cs = lfe_error:format_exception(Class, Error, Stack,
Skip, Format, 1),
io:put_chars(Cs),
halt(?ERROR_STATUS)
end.
%% Implement our own lists functions to get around stacktrace printing
%% problems.
%% foldl(F, Accu, [Hd|Tail]) ->
%% foldl(F, F(Hd, Accu), Tail);
%% foldl(F, Accu, []) when is_function(F, 2) -> Accu.
foreach(F, [Hd | Tail]) ->
F(Hd),
foreach(F, Tail);
foreach(F, []) when is_function(F, 1) -> ok.