Current section
Files
Jump to
Current section
Files
src/econfig_file_writer.erl
%%% -*- erlang -*-
%%%
%%% This file is part of econfig released under the Apache 2 license.
%%% See the NOTICE for more information.
%% @hidden
-module(econfig_file_writer).
-export([save_to_file/2]).
%% @spec save_to_file(
%% Config::{{Section::string(), Option::string()}, Value::string()},
%% File::filename()) -> ok
%% @doc Saves a Section/Key/Value triple to the ini file File::filename()
save_to_file({Section, KVs}, File) ->
{ok, OldFileContents} = file:read_file(File),
Lines0 = re:split(OldFileContents, "\r\n|\n|\r|\032", [{return, list}]),
SectionLine = "[" ++ Section ++ "]",
PKVs = lists:foldl(fun({Key, Val}, Acc) ->
P0 = ["^(", Key, "\\s*=)|\\[[a-zA-Z0-9\.\_-]*\\]"],
{ok, Pattern} = re:compile(P0),
[{Pattern, {Key, Val}} | Acc]
end, [], KVs),
NewLines0 = lists:foldl(fun(PKV, Lines) ->
Lines1 = process_file_lines(Lines, [], SectionLine,
PKV),
lists:reverse(Lines1)
end, Lines0, PKVs),
NewLines = lists:reverse(NewLines0),
NewFileContents = reverse_and_add_newline(strip_empty_lines(NewLines), []),
case file:write_file(File, NewFileContents) of
ok ->
ok;
{error, eacces} ->
{file_permission_error, File};
Error ->
Error
end.
process_file_lines([Section|Rest], SeenLines, Section, PKV) ->
process_section_lines(Rest, [Section|SeenLines], PKV);
process_file_lines([Line|Rest], SeenLines, Section, PKV) ->
process_file_lines(Rest, [Line|SeenLines], Section, PKV);
process_file_lines([], SeenLines, Section, {_, {Key, Value}}) ->
% Section wasn't found. Append it with the option here.
[Key ++ " = " ++ Value, Section, "" | strip_empty_lines(SeenLines)].
process_section_lines([Line|Rest], SeenLines, {Pattern, {Key, Value}}=PKV) ->
case re:run(Line, Pattern, [{capture, all_but_first}]) of
nomatch -> % Found nothing interesting. Move on.
process_section_lines(Rest, [Line|SeenLines], PKV);
{match, []} -> % Found another section. Append the option here.
lists:reverse(Rest) ++
[Line, "", Key ++ " = " ++ Value | strip_empty_lines(SeenLines)];
{match, _} -> % Found the option itself. Replace it.
lists:reverse(Rest) ++ [Key ++ " = " ++ Value | SeenLines]
end;
process_section_lines([], SeenLines, {_Pattern, {Key, Value}}) ->
% Found end of file within the section. Append the option here.
[Key ++ " = " ++ Value | strip_empty_lines(SeenLines)].
reverse_and_add_newline([Line|Rest], Content) ->
reverse_and_add_newline(Rest, [Line, "\n", Content]);
reverse_and_add_newline([], Content) ->
Content.
strip_empty_lines(["" | Rest]) ->
strip_empty_lines(Rest);
strip_empty_lines(All) ->
All.