blob: 98eb54ae9bfb600d3f8ca4b3b67caa229ab9d4c3 [file] [log] [blame]
% 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.
%% @doc Saves a Key/Value pair to a ini file. The Key consists of a Section
%% and Option combination. If that combination is found in the ini file
%% the new value replaces the old value. If only the Section is found the
%% Option and value combination is appended to the Section. If the Section
%% does not yet exist in the ini file, it is added and the Option/Value
%% pair is appended.
%% @see config
-module(config_writer).
-export([save_to_file/2]).
-include("config.hrl").
%% @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, Key}, Value}, File) ->
{ok, OldFileContents} = file:read_file(File),
Lines = re:split(OldFileContents, "\r\n|\n|\r|\032", [{return, list}]),
SectionLine = "[" ++ Section ++ "]",
{ok, Pattern} = re:compile(["^(\\Q", Key, "\\E\\s*=)|\\[[a-zA-Z0-9\.\_-]*\\]"]),
NewLines = process_file_lines(Lines, [], SectionLine, Pattern, Key, Value),
NewFileContents = reverse_and_add_newline(strip_empty_lines(NewLines), []),
file:write_file(File, NewFileContents).
process_file_lines([Section | Rest], SeenLines, Section, Pattern, Key, Value) ->
process_section_lines(Rest, [Section | SeenLines], Pattern, Key, Value);
process_file_lines([Line | Rest], SeenLines, Section, Pattern, Key, Value) ->
process_file_lines(Rest, [Line | SeenLines], Section, Pattern, Key, Value);
process_file_lines([], SeenLines, Section, _Pattern, Key, Value) ->
% Section wasn't found. Append it with the option here.
[maybe_kv(Key, Value), Section, "" | strip_empty_lines(SeenLines)].
process_section_lines([Line | Rest], SeenLines, Pattern, Key, Value) ->
case re:run(Line, Pattern, [{capture, all_but_first}]) of
% Found nothing interesting. Move on.
nomatch ->
process_section_lines(Rest, [Line | SeenLines], Pattern, Key, Value);
% Found another section. Append the option here.
{match, []} ->
lists:reverse(Rest) ++
[Line, "", maybe_kv(Key, Value) | strip_empty_lines(SeenLines)];
% Found the option itself. Replace it.
{match, _} ->
lists:reverse(Rest) ++ [maybe_kv(Key, Value) | SeenLines]
end;
process_section_lines([], SeenLines, _Pattern, Key, Value) ->
% Found end of file within the section. Append the option here.
[maybe_kv(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.
maybe_kv(_, ?DELETE) ->
"";
maybe_kv(Key, Value) ->
Key ++ " = " ++ Value.