diff options
Diffstat (limited to 'lib/reltool/src')
-rw-r--r-- | lib/reltool/src/reltool.app.src | 4 | ||||
-rw-r--r-- | lib/reltool/src/reltool.erl | 45 | ||||
-rw-r--r-- | lib/reltool/src/reltool.hrl | 100 | ||||
-rw-r--r-- | lib/reltool/src/reltool_mod_win.erl | 4 | ||||
-rw-r--r-- | lib/reltool/src/reltool_server.erl | 109 | ||||
-rw-r--r-- | lib/reltool/src/reltool_target.erl | 25 |
6 files changed, 135 insertions, 152 deletions
diff --git a/lib/reltool/src/reltool.app.src b/lib/reltool/src/reltool.app.src index b80753e8fc..4188f341f1 100644 --- a/lib/reltool/src/reltool.app.src +++ b/lib/reltool/src/reltool.app.src @@ -2,7 +2,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009-2010. All Rights Reserved. +%% Copyright Ericsson AB 2009-2011. All Rights Reserved. %% %% 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 @@ -22,8 +22,8 @@ {vsn, "%VSN%"}, {modules, [ - reltool_app_win, reltool, + reltool_app_win, reltool_fgraph, reltool_fgraph_win, reltool_mod_win, diff --git a/lib/reltool/src/reltool.erl b/lib/reltool/src/reltool.erl index 9dd0a24f46..54eb1ca9e1 100644 --- a/lib/reltool/src/reltool.erl +++ b/lib/reltool/src/reltool.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009-2010. All Rights Reserved. +%% Copyright Ericsson AB 2009-2011. All Rights Reserved. %% %% 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 @@ -38,26 +38,26 @@ start() -> %% Start main window process -spec start(options()) -> {ok, window_pid()} | {error, reason()}. -start(Options)when is_list(Options) -> +start(Options) when is_list(Options) -> case start_link(Options) of - {ok, WinPid} -> + {ok, WinPid} = OK -> unlink(WinPid), - {ok, WinPid}; - Other-> - Other + OK; + {error, _Reason} = Error -> + Error end. %% Start main window process with wx debugging enabled --spec debug() -> {ok, window_pid()} | {error, reason()}. +-spec debug() -> {ok, window_pid()} | {error, reason()}. debug() -> start([{wx_debug, 2}]). %% Start main window process with options --spec start_link(options()) -> {ok, window_pid() | {error, reason()}}. +-spec start_link(options()) -> {ok, window_pid()} | {error, reason()}. start_link(Options) when is_list(Options) -> case reltool_sys_win:start_link(Options) of - {ok, WinPid} -> - {ok, WinPid}; + {ok, _WinPid} = OK -> + OK; {error, Reason} -> {error, lists:flatten(io_lib:format("~p", [Reason]))} end. @@ -76,8 +76,8 @@ start_server(Options) -> -spec get_server(window_pid()) -> {ok, server_pid()} | {error, reason()}. get_server(WinPid) -> case reltool_sys_win:get_server(WinPid) of - {ok, ServerPid} -> - {ok, ServerPid}; + {ok, _ServerPid} = OK -> + OK; {error, Reason} -> {error, lists:flatten(io_lib:format("~p", [Reason]))} end. @@ -96,9 +96,9 @@ stop(Pid) when is_pid(Pid) -> end. %% Internal library function --spec eval_server(server(), boolean(), fun((server_pid()) -> term())) -> - {ok, server_pid()} | {error, reason()}. -eval_server(Pid, DisplayWarnings, Fun) +-spec eval_server(server(), boolean(), fun((server_pid()) -> Ret)) -> + Ret | {error, reason()} when Ret :: term(). +eval_server(Pid, _DisplayWarnings, Fun) when is_pid(Pid) -> Fun(Pid); eval_server(Options, DisplayWarnings, Fun) @@ -107,8 +107,8 @@ eval_server(Options, DisplayWarnings, Fun) Res = case start_server(Options) of {ok, Pid} -> apply_fun(Pid, DisplayWarnings, Fun); - {error, Reason} -> - {error, Reason} + {error, _Reason} = Error -> + Error end, process_flag(trap_exit, TrapExit), Res. @@ -122,21 +122,18 @@ apply_fun(Pid, true, Fun) -> {ok, Warnings} -> [io:format("~p: ~s\n", [?APPLICATION, W]) || W <- Warnings], apply_fun(Pid, false, Fun); - {error, Reason} -> + {error, _Reason} = Error -> stop(Pid), - {error, Reason} + Error end. %% Get status about the configuration -type warning() :: string(). --spec get_status(server()) -> - {ok, [warning()]} | {error, reason()}. +-spec get_status(server()) -> {ok, [warning()]} | {error, reason()}. get_status(PidOrOptions) when is_pid(PidOrOptions); is_list(PidOrOptions) -> eval_server(PidOrOptions, false, - fun(Pid) -> - reltool_server:get_status(Pid) - end). + fun(Pid) -> reltool_server:get_status(Pid) end). %% Get reltool configuration -spec get_config(server()) -> {ok, config()} | {error, reason()}. diff --git a/lib/reltool/src/reltool.hrl b/lib/reltool/src/reltool.hrl index 1a34ced89d..93f47f6381 100644 --- a/lib/reltool/src/reltool.hrl +++ b/lib/reltool/src/reltool.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009-2010. All Rights Reserved. +%% Copyright Ericsson AB 2009-2011. All Rights Reserved. %% %% 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 @@ -20,8 +20,8 @@ -define(MISSING_APP_NAME, '*MISSING*'). -define(MISSING_APP_TEXT, "*MISSING*"). --type file() :: string(). --type dir() :: string(). +-type file() :: file:filename(). +-type dir() :: file:filename(). %% app - Include all modules in app file %% ebin - Include all modules on ebin directory %% derived - Include only those modules that others are dependent on @@ -48,7 +48,7 @@ -type mod_name() :: atom(). -type app_name() :: atom(). -type app_vsn() :: string(). % e.g. "4.7" --type app_label() :: string().% e.g. "mnesia" or "mnesia-4.7" +-type app_label() :: string(). % e.g. "mnesia" or "mnesia-4.7" -type app_type() :: permanent | transient | temporary | load | none. -type incl_app() :: app_name(). -type emu_name() :: string(). @@ -93,10 +93,10 @@ | {escript, escript_file(), [escript()]} | {app, app_name(), [app()]}. -type config() :: {sys, [sys()]}. --type option() :: {wx_debug, term()} | - {trap_exit, boolean()} | - config() | - {config, config() | file()}. +-type option() :: {wx_debug, term()} + | {trap_exit, boolean()} + | config() + | {config, config() | file()}. -type options() :: [option()]. -type server_pid() :: pid(). -type window_pid() :: pid(). @@ -110,32 +110,30 @@ -type top_dir() :: file(). -type top_file() :: file(). -type target_spec() :: [target_spec()] - | {create_dir, base_dir(), [target_spec()]} - | {create_dir, base_dir(), top_dir(), [target_spec()]} - | {archive, base_file(), [archive_opt()], [target_spec()]} - | {copy_file, base_file()} - | {copy_file, base_file(), top_file()} - | {write_file, base_file(), iolist()} - | {strip_beam_file, base_file()}. --type target_dir() :: dir(). --type incl_defaults() :: boolean(). --type incl_derived() :: boolean(). --type ets_tab() :: term(). --type status() :: missing | ok. + | {create_dir, base_dir(), [target_spec()]} + | {create_dir, base_dir(), top_dir(), [target_spec()]} + | {archive, base_file(), [archive_opt()], [target_spec()]} + | {copy_file, base_file()} + | {copy_file, base_file(), top_file()} + | {write_file, base_file(), iolist()} + | {strip_beam_file, base_file()}. +-type target_dir() :: dir(). +-type incl_defaults() :: boolean(). +-type incl_derived() :: boolean(). +-type status() :: missing | ok. -record(common, { sys_debug :: term(), wx_debug :: term(), trap_exit :: boolean(), - app_tab :: ets_tab(), - mod_tab :: ets_tab(), - mod_used_by_tab :: ets_tab() - }). - + app_tab :: ets:tab(), + mod_tab :: ets:tab(), + mod_used_by_tab :: ets:tab() + }). -record(mod, - {%% Static + { %% Static name :: mod_name(), app_name :: app_name(), incl_cond :: incl_cond() | undefined, @@ -144,13 +142,12 @@ is_ebin_mod :: boolean(), uses_mods :: [mod_name()], exists :: boolean(), - %% Dynamic status :: status(), used_by_mods :: [mod_name()], is_pre_included :: boolean() | undefined, is_included :: boolean() | undefined - }). + }). -record(app_info, { @@ -166,10 +163,12 @@ env = [] :: [{atom(), term()}], mod = undefined :: {mod_name(), [term()]} | undefined, start_phases = undefined :: [{atom(), term()}] | undefined - }). + }). + +-record(regexp, {source, compiled}). -record(app, - {%% Static info + { %% Static info name :: app_name(), is_escript :: boolean(), use_selected_vsn :: boolean() | undefined, @@ -188,10 +187,10 @@ debug_info :: debug_info() | undefined, app_file :: app_file() | undefined, app_type :: app_type() | undefined, - incl_app_filters :: incl_app_filters(), - excl_app_filters :: excl_app_filters(), - incl_archive_filters :: incl_archive_filters(), - excl_archive_filters :: excl_archive_filters(), + incl_app_filters :: [#regexp{}], + excl_app_filters :: [#regexp{}], + incl_archive_filters :: [#regexp{}], + excl_archive_filters :: [#regexp{}], archive_opts :: [archive_opt()], %% Dynamic @@ -203,13 +202,13 @@ is_pre_included :: boolean(), is_included :: boolean(), rels :: [rel_name()] - }). + }). -record(rel_app, { - name :: app_name(), - app_type :: app_type(), - incl_apps :: [incl_app()] + name :: app_name(), + app_type :: app_type() | undefined, + incl_apps = [] :: [incl_app()] }). -record(rel, @@ -217,11 +216,10 @@ name :: rel_name(), vsn :: rel_vsn(), rel_apps :: [#rel_app{}] - }). + }). -record(sys, - { - %% Sources + { %% Sources root_dir :: dir(), lib_dirs :: [dir()], escripts :: [file()], @@ -234,21 +232,19 @@ rels :: [#rel{}], emu_name :: emu_name(), profile :: profile(), - incl_sys_filters :: incl_sys_filters(), - excl_sys_filters :: excl_sys_filters(), - incl_app_filters :: incl_app_filters(), - excl_app_filters :: excl_app_filters(), - incl_archive_filters :: incl_archive_filters(), - excl_archive_filters :: excl_archive_filters(), + incl_sys_filters :: [#regexp{}], + excl_sys_filters :: [#regexp{}], + incl_app_filters :: [#regexp{}], + excl_app_filters :: [#regexp{}], + incl_archive_filters :: [#regexp{}], + excl_archive_filters :: [#regexp{}], archive_opts :: [archive_opt()], relocatable :: boolean(), rel_app_type :: app_type(), embedded_app_type :: app_type() | undefined, app_file :: app_file(), debug_info :: debug_info() - }). - --record(regexp, {source, compiled}). + }). -define(ERR_IMAGE, 0). -define(WARN_IMAGE, 1). @@ -275,7 +271,7 @@ -define(DEFAULT_INCL_ARCHIVE_FILTERS, [".*"]). -define(DEFAULT_EXCL_ARCHIVE_FILTERS, ["^include\$", "^priv\$"]). --define(DEFAULT_ARCHIVE_OPTS, []). +-define(DEFAULT_ARCHIVE_OPTS, []). -define(DEFAULT_INCL_SYS_FILTERS, [".*"]). -define(DEFAULT_EXCL_SYS_FILTERS, []). @@ -305,5 +301,5 @@ "^erts.*/bin/(start|escript|to_erl|run_erl)(|\\.exe)\$", "^erts.*/bin/.*(debug|pdb)"]). -define(STANDALONE_INCL_APP_FILTERS, ["^ebin", - "^priv"]). + "^priv"]). -define(STANDALONE_EXCL_APP_FILTERS, ["^ebin/.*\\.appup\$"]). diff --git a/lib/reltool/src/reltool_mod_win.erl b/lib/reltool/src/reltool_mod_win.erl index 281d2c8ad4..e1c2fa5100 100644 --- a/lib/reltool/src/reltool_mod_win.erl +++ b/lib/reltool/src/reltool_mod_win.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009-2010. All Rights Reserved. +%% Copyright Ericsson AB 2009-2011. All Rights Reserved. %% %% 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 @@ -744,7 +744,7 @@ create_editor(Parent) -> wxStyledTextCtrl:styleSetFont(Ed, Style, FixedFont), wxStyledTextCtrl:styleSetForeground(Ed, Style, Color) end, - [SetStyle(Style) || Style <- Styles], + lists:foreach(fun (Style) -> SetStyle(Style) end, Styles), wxStyledTextCtrl:setKeyWords(Ed, 0, keyWords()), %% Margins Markers diff --git a/lib/reltool/src/reltool_server.erl b/lib/reltool/src/reltool_server.erl index 039ad56aa8..59f52087a1 100644 --- a/lib/reltool/src/reltool_server.erl +++ b/lib/reltool/src/reltool_server.erl @@ -498,8 +498,8 @@ more_apps_in_rels([{RelName, AppName} = RA | RelApps], Apps, Acc, Status) -> true -> more_apps_in_rels(RelApps, Apps, Acc, Status); false -> - case lists:keysearch(AppName, #app.name, Apps) of - {value, #app{info = #app_info{applications = InfoApps}}} -> + case lists:keyfind(AppName, #app.name, Apps) of + #app{info = #app_info{applications = InfoApps}} -> Extra = [{RelName, N} || N <- InfoApps], {Acc2, Status2} = more_apps_in_rels(Extra, Apps, [RA | Acc], Status), @@ -743,9 +743,9 @@ mod_propagate_is_used_by(_C, []) -> read_apps(C, Sys, [#app{mods = Mods, is_included = IsIncl} = A | Apps], Acc) -> {Mods2, IsIncl2} = read_apps(C, Sys, A, Mods, [], IsIncl), Status = - case lists:keysearch(missing, #mod.status, Mods2) of - {value, _} -> missing; - false -> ok + case lists:keymember(missing, #mod.status, Mods2) of + true -> missing; + false -> ok end, UsesMods = [M#mod.uses_mods || M <- Mods2, M#mod.is_included =:= true], UsesMods2 = lists:usort(lists:flatten(UsesMods)), @@ -820,22 +820,14 @@ filter_app(A) -> A#app.use_selected_vsn =:= undefined -> false; true -> - {Dir, Dirs} = + {Dir, Dirs, OptVsn} = case A#app.use_selected_vsn of undefined -> - {shrinked, []}; + {shrinked, [], undefined}; false -> - {shrinked, []}; + {shrinked, [], undefined}; true -> - {A#app.active_dir, [A#app.active_dir]}; - _ when A#app.is_escript -> - {A#app.active_dir, [A#app.active_dir]} - end, - OptVsn = - case A#app.use_selected_vsn of - undefined -> undefined; - false -> undefined; - true -> A#app.vsn + {A#app.active_dir, [A#app.active_dir], A#app.vsn} end, {true, A#app{active_dir = Dir, sorted_dirs = Dirs, @@ -1087,8 +1079,8 @@ missing_mod(ModName, AppName) -> add_mod_config(Mods, ModConfigs) -> AddConfig = fun(Config, Acc) -> - case lists:keysearch(Config#mod.name, #mod.name, Mods) of - {value, M} -> + case lists:keyfind(Config#mod.name, #mod.name, Mods) of + #mod{} = M -> M2 = M#mod{incl_cond = Config#mod.incl_cond}, lists:keystore(Config#mod.name, #mod.name, Acc, M2); false -> @@ -1179,10 +1171,10 @@ read_config(OldSys, {sys, KeyVals}, Status) -> end, NewSys2 = NewSys#sys{apps = lists:sort(Apps), rels = lists:sort(Rels)}, - case lists:keysearch(NewSys2#sys.boot_rel, + case lists:keymember(NewSys2#sys.boot_rel, #rel.name, NewSys2#sys.rels) of - {value, _} -> + true -> {NewSys2, Status2}; false -> Text2 = lists:concat(["Release " ++ NewSys2#sys.boot_rel, @@ -1418,27 +1410,27 @@ decode(#mod{} = Mod, [{Key, Val} | KeyVals], Status) -> end, decode(Mod2, KeyVals, Status2); decode(#rel{rel_apps = RelApps} = Rel, [RelApp | KeyVals], Status) -> - RA = + {ValidTypesAssigned, RA} = case RelApp of Name when is_atom(Name) -> - #rel_app{name = Name, app_type = undefined, incl_apps = []}; + {true, #rel_app{name = Name}}; {Name, Type} when is_atom(Name) -> - #rel_app{name = Name, app_type = Type, incl_apps = []}; + {is_type(Type), #rel_app{name = Name, app_type = Type}}; {Name, InclApps} when is_atom(Name), is_list(InclApps) -> - #rel_app{name = Name, - app_type = undefined, - incl_apps = InclApps}; + VI = lists:all(fun erlang:is_atom/1, InclApps), + {VI, #rel_app{name = Name, incl_apps = InclApps}}; {Name, Type, InclApps} when is_atom(Name), is_list(InclApps) -> - #rel_app{name = Name, app_type = Type, incl_apps = InclApps}; + VT = is_type(Type), + VI = lists:all(fun erlang:is_atom/1, InclApps), + {VT andalso VI, + #rel_app{name = Name, app_type = Type, incl_apps = InclApps}}; _ -> - #rel_app{incl_apps = []} + {false, #rel_app{incl_apps = []}} end, - IsType = is_type(RA#rel_app.app_type), - NonAtoms = [IA || IA <- RA#rel_app.incl_apps, not is_atom(IA)], - if - IsType, NonAtoms =:= [] -> + case ValidTypesAssigned of + true -> decode(Rel#rel{rel_apps = RelApps ++ [RA]}, KeyVals, Status); - true -> + false -> Text = lists:flatten(io_lib:format("~p", [RelApp])), Status2 = reltool_utils:return_first_error(Status, @@ -1542,10 +1534,9 @@ check_rel(RelName, RelApps, Status) -> patch_erts_version(RootDir, Apps, Status) -> AppName = erts, - case lists:keysearch(AppName, #app.name, Apps) of - {value, Erts} -> + case lists:keyfind(AppName, #app.name, Apps) of + #app{vsn = Vsn} = Erts -> LocalRoot = code:root_dir(), - Vsn = Erts#app.vsn, if LocalRoot =:= RootDir, Vsn =:= "" -> Vsn2 = erlang:system_info(version), @@ -1773,20 +1764,20 @@ files_to_apps(_Escript, [], Acc, _Apps, _OldApps, Status) -> {lists:keysort(#app.name, Acc), Status}. merge_escript_app(AppName, Dir, Info, Mods, Apps, OldApps, Status) -> - case lists:keysearch(AppName, #app.name, OldApps) of - {value, App} -> - ok; - false -> - App = default_app(AppName, Dir) - end, - App2 = App#app{is_escript = true, - label = filename:basename(Dir, ".escript"), - info = Info, - mods = Mods, - active_dir = Dir, - sorted_dirs = [Dir]}, - case lists:keysearch(AppName, #app.name, Apps) of - {value, _} -> + App1 = case lists:keyfind(AppName, #app.name, OldApps) of + #app{} = App -> + App; + false -> + default_app(AppName, Dir) + end, + App2 = App1#app{is_escript = true, + label = filename:basename(Dir, ".escript"), + info = Info, + mods = Mods, + active_dir = Dir, + sorted_dirs = [Dir]}, + case lists:keymember(AppName, #app.name, Apps) of + true -> Error = lists:concat([AppName, ": Application name clash. ", "Escript ", Dir," contains application ", AppName, "."]), @@ -1804,12 +1795,15 @@ merge_app_dirs([{Name, Dir} | Rest], Apps, OldApps) -> %% Initate app Apps2 = sort_app_dirs(Apps), Apps4 = - case lists:keysearch(Name, #app.name, Apps) of + case lists:keyfind(Name, #app.name, Apps) of false -> - case lists:keysearch(Name, #app.name, OldApps) of - {value, OldApp} when OldApp#app.active_dir =:= Dir -> + case lists:keyfind(Name, #app.name, OldApps) of + false -> + App = default_app(Name, Dir), + [App | Apps2]; + #app{active_dir = Dir} = OldApp -> [OldApp | Apps2]; - {value, OldApp} -> + OldApp -> App = case filter_app(OldApp) of {true, NewApp} -> @@ -1818,12 +1812,9 @@ merge_app_dirs([{Name, Dir} | Rest], Apps, OldApps) -> false -> default_app(Name, Dir) end, - [App | Apps2]; - false -> - App = default_app(Name, Dir), [App | Apps2] end; - {value, OldApp} -> + OldApp -> Apps3 = lists:keydelete(Name, #app.name, Apps2), App = OldApp#app{sorted_dirs = [Dir | OldApp#app.sorted_dirs]}, [App | Apps3] diff --git a/lib/reltool/src/reltool_target.erl b/lib/reltool/src/reltool_target.erl index dd6f75b9fc..89ebbd1b5f 100644 --- a/lib/reltool/src/reltool_target.erl +++ b/lib/reltool/src/reltool_target.erl @@ -90,11 +90,11 @@ do_gen_config(#sys{root_dir = RootDir, debug_info = DebugInfo}, InclDefs) -> ErtsItems = - case lists:keysearch(erts, #app.name, Apps) of - {value, Erts} -> - [{erts, do_gen_config(Erts, InclDefs)}]; - false -> - [] + case lists:keyfind(erts, #app.name, Apps) of + false -> + []; + Erts -> + [{erts, do_gen_config(Erts, InclDefs)}] end, AppsItems = [do_gen_config(A, InclDefs) @@ -521,7 +521,6 @@ sort_apps([#app{name = Name, info = Info} = App | Apps], Visited, [], []), - Missing1 = NotFnd1 ++ NotFnd2 ++ Missing, case Uses ++ Incs of [] -> @@ -533,7 +532,7 @@ sort_apps([#app{name = Name, info = Info} = App | Apps], %% The apps in L must be started before the app. %% Check if we have already taken care of some app in L, %% in that case we have a circular dependency. - NewCircular = [N1 || N1 <- L, N2 <- Visited, N1 =:= N2], + NewCircular = [N || #app{name = N} <- L, N2 <- Visited, N =:= N2], Circular1 = case NewCircular of [] -> Circular; _ -> [Name | NewCircular] ++ Circular @@ -558,9 +557,9 @@ sort_apps([], Missing, Circular, _) -> [make_set(Circular), make_set(Missing)]). find_all(CheckingApp, [Name | Names], Apps, Visited, Found, NotFound) -> - case lists:keysearch(Name, #app.name, Apps) of - {value, #app{info = Info} = App} -> - %% It is OK to have a dependecy like + case lists:keyfind(Name, #app.name, Apps) of + #app{info = Info} = App -> + %% It is OK to have a dependency like %% X includes Y, Y uses X. case lists:member(CheckingApp, Info#app_info.incl_apps) of true -> @@ -1232,7 +1231,7 @@ do_eval_spec({strip_beam, File}, _OrigSourceDir, SourceDir, TargetDir) -> reltool_utils:write_file(TargetFile, BeamBin2). cleanup_spec(List, TargetDir) when is_list(List) -> - lists:foreach(fun(F)-> cleanup_spec(F, TargetDir) end, List); + lists:foreach(fun(F) -> cleanup_spec(F, TargetDir) end, List); %% cleanup_spec({source_dir, _SourceDir, Spec}, TargetDir) -> %% cleanup_spec(Spec, TargetDir); cleanup_spec({create_dir, Dir, Files}, TargetDir) -> @@ -1444,8 +1443,8 @@ subst([], _Vars, Result) -> subst_var([$%| Rest], Vars, Result, VarAcc) -> Key = lists:reverse(VarAcc), - case lists:keysearch(Key, 1, Vars) of - {value, {Key, Value}} -> + case lists:keyfind(Key, 1, Vars) of + {Key, Value} -> subst(Rest, Vars, lists:reverse(Value, Result)); false -> subst(Rest, Vars, [$% | VarAcc ++ [$% | Result]]) |