%% 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.