C0 code coverage information

Generated on 2009-08-09 21:22:57 with etap 0.3.4.

Name Total lines Lines of code Total coverage Code coverage
couch_config_writer ?? ?? ??
73% 
....1 % Licensed under the Apache License, Version 2.0 (the "License"); you may not
....2 % use this file except in compliance with the License. You may obtain a copy of
....3 % the License at
....4 %
....5 %   http://www.apache.org/licenses/LICENSE-2.0
....6 %
....7 % Unless required by applicable law or agreed to in writing, software
....8 % distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
....9 % WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
...10 % License for the specific language governing permissions and limitations under
...11 % the License.
...12 
...13 %% @doc Saves a Key/Value pair to a ini file. The Key consists of a Section
...14 %%      and Option combination. If that combination is found in the ini file
...15 %%      the new value replaces the old value. If only the Section is found the
...16 %%      Option and value combination is appended to the Section. If the Section
...17 %%      does not yet exist in the ini file, it is added and the Option/Value
...18 %%      pair is appended.
...19 %% @see couch_config
...20 
...21 -module(couch_config_writer).
...22 -include("couch_db.hrl").
...23 
...24 -export([save_to_file/2]).
...25 
...26 %% @spec save_to_file(
...27 %%           Config::{{Section::string(), Option::string()}, Value::string()},
...28 %%           File::filename()) -> ok
...29 %% @doc Saves a Section/Key/Value triple to the ini file File::filename()
...30 save_to_file({{Section, Option}, Value}, File) ->
...31 
...32     ?LOG_DEBUG("saving to file '~s', Config: '~p'", [File, {{Section, Option}, Value}]),
...33 
...34     % open file and create a list of lines
...35     {ok, Stream} = file:read_file(File),
...36     OldFileContents = binary_to_list(Stream),
...37     {ok, Lines} = regexp:split(OldFileContents, "\r\n|\n|\r|\032"),
...38 
...39     % prepare input variables
...40     SectionName = "[" ++ Section ++ "]",
...41     OptionList = Option,
...42 
...43     % produce the contents for the config file
...44     NewFileContents =
...45     case {NewFileContents2, DoneOptions} = save_loop({{SectionName, OptionList}, Value}, Lines, "", "", []) of
...46         % we didn't change anything, that means we couldn't find a matching
...47         % [ini section] in which case we just append a new one.
...48         {OldFileContents, DoneOptions} ->
...49             % but only if we haven't actually written anything.
...50             case lists:member(OptionList, DoneOptions) of
...51                 true -> OldFileContents;
...52                 _ -> append_new_ini_section({{SectionName, OptionList}, Value}, OldFileContents)
...53             end;
...54         _ ->
...55             NewFileContents2
...56     end,
...57 
...58     ok = file:write_file(File, list_to_binary(NewFileContents)),
...59     ok.
...60 
...61 %% @doc Iterates over the lines of an ini file and replaces or adds a new
...62 %%      configuration directive.
...63 save_loop({{Section, Option}, Value}, [Line|Rest], OldCurrentSection, Contents, DoneOptions) ->
...64 
...65     % if we find a new [ini section] (Section), save that for reference
...66     NewCurrentSection = parse_module(Line, OldCurrentSection),
...67     % if the current Section is the one we want to change, try to match
...68     % each line with the Option
...69     NewContents =
...70     case NewCurrentSection of
...71     Section ->
...72         case OldCurrentSection of
...73         NewCurrentSection -> % we already were in [Section]
...74             case lists:member(Option, DoneOptions) of
...75             true -> % we already replaced Option, do nothing
...76                 DoneOptions2 = DoneOptions,
...77                 Line;
...78             _ -> % we haven't written our Option yet
...79                 case parse_variable(Line, Option, Value) of
...80                 nomatch ->
...81                     DoneOptions2 = DoneOptions,
...82                     Line;
...83                 NewLine ->
...84                     DoneOptions2 = [Option|DoneOptions],
...85                     NewLine
...86                 end
...87             end;
...88         _ -> % we got into a new [section]
...89             {NewLine, DoneOptions2} = append_var_to_section(
...90                 {{Section, Option}, Value},
...91                 Line,
...92                 OldCurrentSection,
...93                 DoneOptions),
...94             NewLine
...95         end;
...96     _ -> % we are reading [NewCurrentSection]
...97         {NewLine, DoneOptions2} = append_var_to_section(
...98             {{Section, Option}, Value},
...99             Line,
..100             OldCurrentSection,
..101             DoneOptions),
..102         NewLine
..103     end,
..104     % clumsy way to only append a newline character if the line is not empty. We need this to
..105     % avoid having a newline inserted at the top of the target file each time we save it.
..106     Contents2 = case Contents of "" -> ""; _ -> Contents ++ "\n" end,
..107     % go to next line
..108     save_loop({{Section, Option}, Value}, Rest, NewCurrentSection, Contents2 ++ NewContents, DoneOptions2);
..109 
..110 save_loop({{Section, Option}, Value}, [], OldSection, NewFileContents, DoneOptions) ->
..111     case lists:member(Option, DoneOptions) of
..112         % append Deferred Option
..113         false when Section == OldSection ->
..114             {NewFileContents ++ "\n" ++ Option ++ " = " ++ Value ++ "\n", DoneOptions};
..115         % we're out of new lines, just return the new file's contents
..116         _ -> {NewFileContents, DoneOptions}
..117     end.
..118 
..119 append_new_ini_section({{SectionName, Option}, Value}, OldFileContents) ->
..120     OldFileContents ++ "\n" ++ SectionName ++ "\n" ++  Option ++ " = " ++ Value ++ "\n".
..121 
..122 append_var_to_section({{Section, Option}, Value}, Line, OldCurrentSection, DoneOptions) ->
..123     case OldCurrentSection of
..124         Section -> % append Option to Section
..125             case lists:member(Option, DoneOptions) of
..126             false ->
..127                 {Option ++ " = " ++ Value ++ "\n\n" ++ Line, [Option|DoneOptions]};
..128             _ ->
..129                 {Line, DoneOptions}
..130             end;
..131         _ ->
..132             {Line, DoneOptions}
..133         end.
..134 
..135 %% @spec parse_module(Line::string(), OldSection::string()) -> string()
..136 %% @doc Tries to match a line against a pattern specifying a ini module or
..137 %%      section ("[Section]"). Returns OldSection if no match is found.
..138 parse_module(Line, OldSection) ->
..139     case regexp:match(Line, "^\\[([a-zA-Z0-9\_-]*)\\]$") of
..140         nomatch ->
..141             OldSection;
..142         {error, Error} ->
..143             io:format("ini file regex error module: '~s'~n", [Error]),
..144             OldSection;
..145         {match, Start, Length} ->
..146             string:substr(Line, Start, Length)
..147     end.
..148 
..149 %% @spec parse_variable(Line::string(), Option::string(), Value::string()) ->
..150 %%         string() | nomatch
..151 %% @doc Tries to match a variable assignment in Line. Returns nomatch if the
..152 %%      Option is not found. Returns a new line composed of the Option and
..153 %%      Value otherwise.
..154 parse_variable(Line, Option, Value) ->
..155     case regexp:match(Line, "^" ++ Option ++ "\s?=") of
..156         nomatch ->
..157             nomatch;
..158         {error, Error}->
..159             io:format("ini file regex error variable: '~s'~n", [Error]),
..160             nomatch;
..161         {match, _Start, _Length} ->
..162             Option ++ " = " ++ Value
..163     end.

Generated using etap 0.3.4.