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