classdef IniConfig < handle
%IniConfig - The class for working with configurations of settings and INI-files.
% This class allows you to create configurations of settings, and to manage them.
% The structure of the storage settings is similar to the structure of
% the storage the settings in the INI-file format.
% The class allows you to import settings from the INI-file and to export
% the settings in INI-file.
% Can be used for reading/writing data in the INI-file and managing
% settings of application.
%
%
% Using:
% ini = IniConfig()
%
% Public Properties:
% Enter this command to get the properties:
% >> properties IniConfig
%
% Public Methods:
% Enter this command to get the methods:
% >> methods IniConfig
%
% Enter this command to get more info of method:
% >> help IniConfig/methodname
%
%
% Config Syntax:
%
% ; some comments
%
% [Section1] ; allowed the comment to section
% ; comment on the section
% key1 = value_1 ; allowed a comment to an individual parameter
% key2 = value_2
%
% [Section2]
% key1 = value_1.1, value_1.2 ; array data
% key2 = value_2
% ...
%
% Note:
% * There may be spaces in the names of sections and keys
% * Keys should not be repeated in the section (will read the last)
% * Sections should not be repeated in the config (will read the last)
%
% Supported data types:
% * numeric scalars and vectors
% * strings
%
%
% Example:
% ini = IniConfig();
% ini.ReadFile('example.ini')
% ini.ToString()
%
% Example:
% ini = IniConfig();
% ini.ReadFile('example.ini')
% sections = ini.GetSections()
% [keys, count_keys] = ini.GetKeys(sections{1})
% values = ini.GetValues(sections{1}, keys)
% new_values(:) = {rand()};
% ini.SetValues(sections{1}, keys, new_values, '%.3f')
% ini.WriteFile('example1.ini')
%
% Example:
% ini = IniConfig();
% ini.AddSections({'Some Section 1', 'Some Section 2'})
% ini.AddKeys('Some Section 1', {'some_key1', 'some_key2'}, {'hello!', [10, 20]})
% ini.AddKeys('Some Section 2', 'some_key3', true)
% ini.AddKeys('Some Section 2', 'some_key1')
% ini.WriteFile('example2.ini')
%
% Example:
% ini = IniConfig();
% ini.AddSections('Some Section 1')
% ini.AddKeys('Some Section 1', 'some_key1', 'hello!')
% ini.AddKeys('Some Section 1', {'some_key2', 'some_key3'}, {[10, 20], [false, true]})
% ini.WriteFile('example31.ini')
% ini.RemoveKeys('Some Section 1', {'some_key1', 'some_key3'})
% ini.RenameKeys('Some Section 1', 'some_key2', 'renamed_some_key2')
% ini.RenameSections('Some Section 1', 'Renamed Section 1')
% ini.WriteFile('example32.ini')
%
%
% See also:
% textscan, containers.Map
%
%
% Author: Iroln <esp.home@gmail.com>
% Version: 1.2
% First release: 25.07.09
% Last revision: 21.03.10
% Copyright: (c) 2009-2010 Evgeny Prilepin aka Iroln
%
% Bug reports, questions, etc. can be sent to the e-mail given above.
%
properties (GetAccess = 'public', SetAccess = 'private')
comment_style = ';' % style of comments
count_sections = 0 % number of sections
count_all_keys = 0 % number of all keys
end
properties (GetAccess = 'private', SetAccess = 'private')
config_data_array = {}
indicies_of_sections
indicies_of_empty_strings
count_strings = 0
count_empty_strings = 0
is_created_configuration = false
end
%======================================================================
methods
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Public Methods
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%------------------------------------------------------------------
function obj = IniConfig()
%IniConfig - constructor
% To Create new object with empty default configuration.
%
% Using:
% obj = IniConfig()
%
% Input:
% none
%
% Output:
% obj - an instance of class IniConfig
% -------------------------------------------------------------
obj.CreateIni();
end
%------------------------------------------------------------------
function CreateIni(obj)
%CreateIni - create new empty configuration
%
% Using:
% CreateIni()
%
% Input:
% none
%
% Output:
% none
% -------------------------------------------------------------
obj.config_data_array = cell(2,3);
obj.config_data_array(:,:) = {''};
obj.updateCountStrings();
obj.updateSectionsInfo();
obj.updateEmptyStringsInfo();
obj.is_created_configuration = true;
end
%------------------------------------------------------------------
function status = ReadFile(obj, file_name, comment_style)
%ReadFile - to read in the object the config data from a INI file
%
% Using:
% status = ReadFile(file_name, comment_style)
%
% Input:
% file_name - INI file name
% comment_style - style of comments in INI file
%
% Output:
% status - 1 (true) - success, 0 (false) - failed
% -------------------------------------------------------------
error(nargchk(2, 3, nargin));
CheckIsString(file_name);
if (nargin == 3)
obj.comment_style = ValidateCommentStyle(comment_style);
end
% Get data from file
[file_data, status] = GetDataFromFile(file_name);
if (status)
obj.count_strings = size(file_data, 1);
obj.config_data_array = ...
ParseConfigData(file_data, obj.comment_style);
obj.updateSectionsInfo();
obj.updateEmptyStringsInfo();
obj.updateCountKeysInfo();
obj.is_created_configuration = true;
end
end
%------------------------------------------------------------------
function status = IsSections(obj, section_names)
%IsSections - determine whether there is a sections
%
% Using:
% status = IsSections(section_names)
%
% Input:
% section_names - name of section(s)
%
% Output:
% status - 1 (true) - yes, 0 (false) - no
% -------------------------------------------------------------
error(nargchk(2, 2, nargin));
section_names = DataToCell(section_names);
section_names = cellfun(@(x) obj.validateSectionName(x), ...
section_names, 'UniformOutput', false);
status = cellfun(@(x) obj.isSection(x), ...
section_names, 'UniformOutput', true);
end
%------------------------------------------------------------------
function [section_names, count_sect] = GetSections(obj)
%GetSections - get names of all sections
%
% Using:
% section_names = GetSections()
% [names_sect, count_sect] = GetSections()
%
% Input:
% none
%
% Output:
% section_names - cell array with the names of sections
% count_sect - number of sections in configuration
% -------------------------------------------------------------
error(nargchk(1, 1, nargin));
section_names = obj.config_data_array(obj.indicies_of_sections, 1);
% section_names = strrep(section_names, '[', '');
% section_names = strrep(section_names, ']', '');
count_sect = obj.count_sections;
end
%------------------------------------------------------------------
function status = AddSections(obj, section_names)
%AddSections - add sections to end configuration
%
% Using:
% status = AddSections(section_names)
%
% Input:
% section_names - name of section
%
% Output:
% status - 1 (true) - success, 0 (false) - failed
% -------------------------------------------------------------
error(nargchk(2, 2, nargin));
section_names = DataToCell(section_names);
section_names = cellfun(@(x) obj.validateSectionName(x), ...
section_names, 'UniformOutput', false);
status = cellfun(@(x) obj.addSection(x), ...
section_names, 'UniformOutput', true);
end
%------------------------------------------------------------------
function status = InsertSections(obj, positions, section_names)
%InsertSections - insert sections to given positions
%
% Using:
% status = InsertSections(positions, section_names)
%
% Input
% positions - positions of sections
% section_names - names of sections
%
% Output:
% status - 1 (true) - success, 0 (false) - failed
% -------------------------------------------------------------
error(nargchk(3, 3, nargin));
positions = DataToCell(positions);
section_names = DataToCell(section_names);
CheckEqualNumberElems(positions, section_names);
section_names = cellfun(@(x) obj.validateSectionName(x), ...
section_names, 'UniformOutput', false);
status = cellfun(@(x, y) obj.insertSection(x, y), ...
positions, section_names, 'UniformOutput', true);
end
%------------------------------------------------------------------
function status = RemoveSections(obj, section_names)
%RemoveSections - remove given section
%
% Using:
% status = RemoveSections(section_names)
%
% Input:
% section_names - names of sections
%
% Output:
% status - 1 (true) - success, 0 (false) - failed
% -------------------------------------------------------------
error(nargchk(2, 2, nargin));
section_names = DataToCell(section_names);
status = cellfun(@(x) obj.removeSection(x), ...
section_names, 'UniformOutput', true);
end
%------------------------------------------------------------------
function status = RenameSections(obj, old_section_names, new_section_names)
%RenameSections - rename given sections
%
% Using:
% status = RenameSections(old_section_names, new_section_names)
%
% Input:
% old_section_names - old names of sections
% new_section_names - new names of sections
%
% Output:
% status - 1 (true) - success, 0 (false) - failed
% -------------------------------------------------------------
error(nargchk(3, 3, nargin));
old_section_names = DataToCell(old_section_names);
new_section_names = DataToCell(new_section_names);
CheckEqualNumberElems(old_section_names, new_section_names);
status = cellfun(@(x, y) obj.renameSection(x, y), ...
old_section_names, new_section_names, 'UniformOutput', true);
end
%------------------------------------------------------------------
function status = IsKeys(obj, section_name, key_names)
%IsKeys - determine whether there is a keys in a given section
%
% Using:
% status = IsKeys(section_name, key_names)
%
% Input:
% key_names - name of keys
%
% Output:
% status - 1 (true) - yes, 0 (false) - no
% -------------------------------------------------------------
error(nargchk(3, 3, nargin));
key_names = DataToCell(key_names);
section_name = obj.validateSectionName(section_name);
section_names = PadDataToCell(section_name, numel(key_names));
status = cellfun(@(x, y) obj.isKey(x, y), ...
section_names, key_names, 'UniformOutput', 1);
end
%------------------------------------------------------------------
function [key_names, count_keys] = GetKeys(obj, section_name)
%GetKeys - get names of all keys from given section
%
% Using:
% key_names = GetKeys(section_name)
% [key_names, count_keys] = GetKeys(section_name)
%
% Input:
% section_name - name of section
%
% Output:
% key_names - cell array with the names of keys
% count_keys - number of keys in given section
% -------------------------------------------------------------
error(nargchk(2, 2, nargin));
section_name = obj.validateSectionName(section_name);
[key_names, count_keys] = obj.getKeys(section_name);
end
%------------------------------------------------------------------
function [status, tf_set_values] = ...
AddKeys(obj, section_name, key_names, key_values, value_formats)
%AddKeys - add keys in a end given section
%
% Using:
% status = AddKeys(section_name, key_names)
% status = AddKeys(section_name, key_names, key_values)
% status = AddKeys(section_name, key_names, key_values, value_formats)
% [status, tf_set_values] = AddKeys(...)
%
% Input:
% section_name -- name of section
% key_names -- names of keys
% key_values -- values of keys (optional)
% value_formats --
%
% Output:
% status -- 1 (true): Success, status - 0 (false): Failed
% tf_set_values -- 1 (true): Success, status - 0 (false): Failed
% -------------------------------------------------------------
error(nargchk(3, 5, nargin));
key_names = DataToCell(key_names);
num_of_keys = numel(key_names);
if (nargin < 5)
value_formats = PadDataToCell('', num_of_keys);
end
if (nargin < 4)
key_values = PadDataToCell('', num_of_keys);
end
key_values = DataToCell(key_values);
value_formats = DataToCell(value_formats);
CheckEqualNumberElems(key_names, key_values);
CheckEqualNumberElems(key_values, value_formats);
key_values = ValidateValues(key_values);
section_name = obj.validateSectionName(section_name);
section_names = PadDataToCell(section_name, num_of_keys);
[status, tf_set_values] = cellfun(@(a, b, c, d) obj.addKey(a, b, c, d), ...
section_names, key_names, key_values, value_formats, 'UniformOutput', 1);
end
%------------------------------------------------------------------
function [status, tf_set_values] = InsertKeys(obj, ...
section_name, key_positions, key_names, key_values, value_formats)
%InsertKeys - insert keys into the specified positions in a given section
%
% Using:
% status = InsertKeys(section_name, key_positions, key_names)
% status = InsertKeys(section_name, key_positions, key_names, key_values)
% status = InsertKeys(section_name, key_positions, key_names, key_values, value_formats)
% [status, tf_set_values] = InsertKeys(...)
%
% Input:
% section_name -- name of section
% key_positions -- positions of keys in section
% key_names -- names of keys
% key_values -- values of keys (optional)
% value_formats --
%
% Output:
% status - 1 (true): Success, status - 0 (false): Failed
% tf_set_values - 1 (true): Success, status - 0 (false): Failed
% -------------------------------------------------------------
error(nargchk(4, 6, nargin));
key_positions = DataToCell(key_positions);
key_names = DataToCell(key_names);
num_of_keys = numel(key_names);
CheckEqualNumberElems(key_positions, key_names);
if (nargin < 6)
value_formats = PadDataToCell('', num_of_keys);
end
if (nargin < 5)
key_values = PadDataToCell('', num_of_keys);
end
key_values = DataToCell(key_values);
value_formats = DataToCell(value_formats);
CheckEqualNumberElems(key_names, key_values);
CheckEqualNumberElems(key_values, value_formats);
key_values = ValidateValues(key_values);
section_name = obj.validateSectionName(section_name);
section_names = PadDataToCell(section_name, num_of_keys);
[status, tf_set_values] = ...
cellfun(@(a, b, c, d, e) obj.insertKey(a, b, c, d, e), ...
section_names, key_positions, key_names, ...
key_values, value_formats, 'UniformOutput', true);
end
%------------------------------------------------------------------
function status = RemoveKeys(obj, section_name, key_names)
%RemoveKeys - remove the keys from a given section
%
% Using:
% status = RemoveKeys(section_name, key_names)
%
% Input:
% section_name - name of section
% key_names - names of keys
%
% Output:
% status - 1 (true) - success, 0 (false) - failed
% -------------------------------------------------------------
error(nargchk(3, 3, nargin));
key_names = DataToCell(key_names);
section_name = obj.validateSectionName(section_name);
section_names = PadDataToCell(section_name, numel(key_names));
status = cellfun(@(a, b) obj.removeKey(a, b), ...
section_names, key_names, 'UniformOutput', true);
end
%------------------------------------------------------------------
function status = RenameKeys(obj, section_name, old_key_names, new_key_names)
%RenameKeys - rename the keys in a given section
%
% Using:
% status = RenameKeys(section_name, old_key_names, new_key_names)
%
% Input:
% section_name - name of section
% old_key_names - old names of keys
% new_key_names - new names of keys
%
% Output:
% status - 1 (true) - success, 0 (false) - failed
% -------------------------------------------------------------
error(nargchk(4, 4, nargin));
old_key_names = DataToCell(old_key_names);
new_key_names = DataToCell(new_key_names);
CheckEqualNumberElems(old_key_names, new_key_names);
section_name = obj.validateSectionName(section_name);
section_names = PadDataToCell(section_name, numel(old_key_names));
status = cellfun(@(a, b, c) obj.renameKey(a, b, c), ...
section_names, old_key_names, ...
new_key_names, 'UniformOutput', true);
end
%------------------------------------------------------------------
function [values, status] = GetValues(obj, section_name, key_names, default_values)
%GetValues - get values of keys from given section
%
% Using:
% values = GetValues(section_name, key_names)
% values = GetValues(section_name, key_names, default_values)
%
% Input:
% section_name -- name of given section
% key_names -- names of given keys
% default_values -- values of keys that are returned by default
%
% Output:
% values -- cell array with the values of keys
% status -- 1 (true) - success, 0 (false) - failed
% -------------------------------------------------------------
error(nargchk(2, 4, nargin));
% if (nargin < 2)
% % get all values
% sections = obj.GetSections();
%
% values = {};
% status = [];
% for i = 1:numel(sections)
% [vals, tf] = obj.GetValues(sections{i});
% values = cat(1, values, vals);
% status = cat(1, status, tf);
% end
% return;
% end
section_name = obj.validateSectionName(section_name);
if (nargin < 3)
% get all values from given section
key_names = obj.getKeys(section_name);
if isempty(key_names)
values = {};
status = false;
return;
end
end
if iscell(key_names)
is_cell = true;
else
is_cell = false;
end
key_names = DataToCell(key_names);
if (nargin < 4)
default_values = PadDataToCell([], numel(key_names));
end
default_values = DataToCell(default_values);
default_values = ValidateValues(default_values);
CheckEqualNumberElems(key_names, default_values);
section_names = PadDataToCell(section_name, numel(key_names));
[values, status] = cellfun(@(x, y, z) obj.getValue(x, y, z), ...
section_names, key_names, default_values, 'UniformOutput', false);
if (~is_cell)
values = values{1};
end
status = cell2mat(status);
end
%------------------------------------------------------------------
function status = SetValues(obj, section_name, key_names, key_values, value_formats)
%SetValues - set values for given keys from given section
%
% Using:
% status = SetValues(section_name, key_names, key_values)
% status = SetValues(section_name, key_names, key_values, value_formats)
%
% Input:
% section_name -- name of given section (must be string)
% key_names -- names of given keys (must be cell array of strings or string)
% key_values -- values of keys (must be cell array or one value)
% value_formats --
%
% Output:
% status -- 1 (true) - success, 0 (false) - failed
% -------------------------------------------------------------
error(nargchk(4, 5, nargin));
key_names = DataToCell(key_names);
num_of_keys = numel(key_names);
if (nargin < 5)
value_formats = PadDataToCell('', num_of_keys);
end
key_values = DataToCell(key_values);
value_formats = DataToCell(value_formats);
CheckEqualNumberElems(key_names, key_values);
CheckEqualNumberElems(key_values, value_formats);
key_values = ValidateValues(key_values);
section_name = obj.validateSectionName(section_name);
section_names = PadDataToCell(section_name, num_of_keys);
status = cellfun(@(a, b, c, d) obj.setValue(a, b, c, d), ...
section_names, key_names, key_values, value_formats, 'UniformOutput', true);
end
%------------------------------------------------------------------
function varargout = ToString(obj, section_name)
%ToString - export configuration to string or display
%
% Using:
% ToString()
% ToString(section_name)
% str = ToString(...)
%
% Input:
% section_name - name of sections for export (optional)
%
% Output:
% str - string with full or section configuration (optional)
% -------------------------------------------------------------
%FIXME: , ,
error(nargchk(1, 2, nargin));
if (nargin < 2)
is_full_export = true;
else
section_name = obj.validateSectionName(section_name);
is_full_export = false;
end
if is_full_export
count_str = obj.count_strings;
indicies = 1:count_str;
else
first_index = getSectionIndex(obj, section_name);
key_indicies = obj.getKeysIndexes(section_name);
if isempty(key_indicies)
last_index = first_index;
else
last_index = key_indicies(end);
end
indicies = first_index:last_index;
end
indicies_of_sect = obj.indicies_of_sections;
config_data = obj.config_data_array;
str = '';
conf_str = sprintf('\n');
for k = indicies
if isempty(config_data{k,1})
if isempty(config_data{k,3})
str = sprintf('\n');
else
comment_str = config_data{k,3};
str = sprintf('%s\n', comment_str);
end
elseif ~isempty(indicies_of_sect(indicies_of_sect == k))
if is_full_export
if isempty(config_data{k,3})
section_str = config_data{k,1};
str = sprintf('%s\n', section_str);
else
section_str = config_data{k,1};
comment_str = config_data{k,3};
str = sprintf('%s %s\n', ...
section_str, comment_str);
end
end
elseif ~isempty(config_data{k,1}) && ...
isempty(indicies_of_sect(indicies_of_sect == k))
if isempty(config_data{k,3})
key_str = config_data{k,1};
val_str = config_data{k,2};
str = sprintf('%s=%s\n', key_str, val_str);
else
key_str = config_data{k,1};
val_str = config_data{k,2};
comment_str = config_data{k,3};
str = sprintf('%s=%s %s\n', ...
key_str, val_str, comment_str);
end
end
conf_str = sprintf('%s%s', conf_str, str);
end
if (nargout == 0)
fprintf(1, '%s\n', conf_str);
elseif (nargout == 1)
varargout{1} = conf_str(2:end);
else
error('Too many output arguments.')
end
end
%------------------------------------------------------------------
function status = WriteFile(obj, file_name)
%WriteFile - write to the configuration INI file on disk
%
% Using:
% status = WriteFile(file_name)
%
% Input:
% file_name - name of output INI file
%
% Output:
% status - 1 (true) - success, 0 (false) - failed
% -------------------------------------------------------------
error(nargchk(2, 2, nargin));
CheckIsString(file_name);
fid = fopen(file_name, 'w');
if (fid ~= -1)
str = obj.ToString();
fprintf(fid, '%s', str);
fclose(fid);
status = true;
else
status = false;
return;
end
end
end % public methods
%----------------------------------------------------------------------
%======================================================================
methods (Access = 'private')
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Private Methods
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%------------------------------------------------------------------
function num = nameToNumSection(obj, section_name)
%nameToNumSection - get number of section
section_names = obj.GetSections();
int_ind = find(strcmp(section_names, section_name));
if ~isempty(int_ind)
% If the section is not unique, then choose the latest
num = int_ind(end);
else
num = [];
end
end
%------------------------------------------------------------------
function sect_index = getSectionIndex(obj, section_name)
%getSectionIndex - get index of section in config data
num = obj.nameToNumSection(section_name);
sect_index = obj.indicies_of_sections(num);
end
%------------------------------------------------------------------
function [key_indicies, count_keys] = getKeysIndexes(obj, section_name)
%getKeysIndexes - get keys indices from given section
sect_num = obj.nameToNumSection(section_name);
if isempty(sect_num)
key_indicies = [];
count_keys = 0;
return;
elseif (sect_num == obj.count_sections)
key_indicies = ...
obj.indicies_of_sections(sect_num)+1:obj.count_strings;
else
key_indicies = ...
obj.indicies_of_sections(sect_num)+1:obj.indicies_of_sections(sect_num+1)-1;
end
indicies_of_empty = obj.indicies_of_empty_strings;
empty_indicies = ismember(key_indicies, indicies_of_empty);
% empty_indicies = cellfun('isempty', ...
% obj.config_data_array(key_indicies, 1));
key_indicies(empty_indicies) = [];
key_indicies = key_indicies(:);
count_keys = length(key_indicies);
end
%------------------------------------------------------------------
function ind = getKeyIndex(obj, section_name, key_name)
%getKeyIndex - get key index
key_names = obj.getKeys(section_name);
key_indicies = obj.getKeysIndexes(section_name);
int_ind = strcmp(key_names, key_name);
ind = key_indicies(int_ind);
end
%------------------------------------------------------------------
function updateSectionsInfo(obj)
%updateSectionsInfo - update info about sections
keys_data = obj.config_data_array(:,1);
sect_indicies_cell = regexp(keys_data, '^\[.*\]$');
obj.indicies_of_sections = ...
find(~cellfun('isempty', sect_indicies_cell));
obj.count_sections = length(obj.indicies_of_sections);
end
%------------------------------------------------------------------
function updateCountKeysInfo(obj)
%UpdateCountKeys - update full number of keys
obj.count_all_keys = ...
obj.count_strings - obj.count_sections - obj.count_empty_strings;
end
%------------------------------------------------------------------
function updateEmptyStringsInfo(obj)
%updateEmptyStringsInfo - update info about empty strings
keys_data = obj.config_data_array(:,1);
indicies_of_empty_cell = strcmp('', keys_data);
obj.indicies_of_empty_strings = find(indicies_of_empty_cell);
obj.count_empty_strings = length(obj.indicies_of_empty_strings);
end
%------------------------------------------------------------------
function updateCountStrings(obj)
%updateCountStrings - update full number of sections
obj.count_strings = size(obj.config_data_array, 1);
end
%------------------------------------------------------------------
function status = isUniqueKeyName(obj, section_name, key_name)
%isUniqueKeyName - check whether the name of the key unique
keys = obj.getKeys(section_name);
status = ~any(strcmp(key_name, keys));
end
%------------------------------------------------------------------
function status = isUniqueSectionName(obj, section_name)
%isUniqueKeyName - check whether the name of the section a unique
sections = obj.GetSections();
status = ~any(strcmp(section_name, sections));
end
%------------------------------------------------------------------
function status = isSection(obj, section_name)
%isSection - determine whether there is a section
% section_names = obj.GetSections();
data = obj.config_data_array(:, 1);
int_ind = find(strcmp(data, section_name), 1);
if ~isempty(int_ind)
status = true;
else
status = false;
end
end
%------------------------------------------------------------------
function section_name = validateSectionName(obj, section_name)
%validateSectionName - check the name of the section
CheckIsString(section_name);
section_name = section_name(:)';
section_name = strtrim(section_name);
if ~isempty(section_name)
sect_indicies_cell = ...
regexp(section_name, '^\[.*\]$', 'once');
indicies_cell_comment = ...
regexp(section_name, obj.comment_style, 'once');
if ~isempty(indicies_cell_comment)
section_name = [];
return;
end
if isempty(sect_indicies_cell)
section_name = ['[', section_name, ']'];
end
else
section_name = [];
end
end
%------------------------------------------------------------------
function status = addSection(obj, section_name)
%addSection - add section to end configuration
status = obj.insertSection(obj.count_sections+1, section_name);
end
%------------------------------------------------------------------
function status = insertSection(obj, section_pos, section_name)
%insertSection - insert section to given position
CheckIsScalarPositiveInteger(section_pos);
if (section_pos > obj.count_sections+1)
section_pos = obj.count_sections+1;
end
if ~isempty(section_name)
is_unique_sect = obj.isUniqueSectionName(section_name);
if ~is_unique_sect
status = false;
return;
end
if (section_pos <= obj.count_sections && obj.count_sections > 0)
sect_ind = obj.indicies_of_sections(section_pos);
elseif (section_pos == 1 && obj.count_sections == 0)
sect_ind = 1;
obj.config_data_array = {};
elseif (section_pos == obj.count_sections+1)
sect_ind = obj.count_strings+1;
end
new_data = cell(2,3);
new_data(1,:) = {section_name, '', ''};
new_data(2,:) = {''};
obj.config_data_array = ...
InsertCell(obj.config_data_array, sect_ind, new_data);
obj.updateCountStrings();
obj.updateSectionsInfo();
obj.updateEmptyStringsInfo();
status = true;
else
status = false;
end
end
%------------------------------------------------------------------
function status = removeSection(obj, section_name)
%removeSection - remove given section
section_name = obj.validateSectionName(section_name);
sect_num = obj.nameToNumSection(section_name);
if ~isempty(sect_num)
if (sect_num < obj.count_sections)
first_ind = obj.indicies_of_sections(sect_num);
last_ind = obj.indicies_of_sections(sect_num+1)-1;
elseif (sect_num == obj.count_sections)
first_ind = obj.indicies_of_sections(sect_num);
last_ind = obj.count_strings;
end
obj.config_data_array(first_ind:last_ind,:) = [];
obj.updateCountStrings();
obj.updateSectionsInfo();
obj.updateEmptyStringsInfo();
obj.updateCountKeysInfo();
status = true;
else
status = false;
end
end
%------------------------------------------------------------------
function status = renameSection(obj, old_section_name, new_section_name)
%renameSection - rename given section
old_section_name = obj.validateSectionName(old_section_name);
new_section_name = obj.validateSectionName(new_section_name);
sect_num = obj.nameToNumSection(old_section_name);
if (~isempty(new_section_name) && ~isempty(sect_num))
sect_ind = obj.indicies_of_sections(sect_num);
obj.config_data_array(sect_ind, 1) = {new_section_name};
status = true;
else
status = false;
end
end
%------------------------------------------------------------------
function key_name = validateKeyName(obj, key_name)
%validateKeyName - check the name of the key
CheckIsString(key_name);
key_name = key_name(:)';
key_name = strtrim(key_name);
indicies_cell = regexp(key_name, '^\[.*\]$', 'once');
indicies_cell_comment = regexp(key_name, obj.comment_style, 'once');
if (isempty(key_name) || ~isempty(indicies_cell) || ...
~isempty(indicies_cell_comment))
key_name = '';
end
end
%------------------------------------------------------------------
function status = isKey(obj, section_name, key_name)
%isKey - determine whether there is a key in a given section
key_name = obj.validateKeyName(key_name);
if ~isempty(key_name)
status = ~obj.isUniqueKeyName(section_name, key_name);
else
status = false;
end
end
%------------------------------------------------------------------
function [status, write_value] = ...
addKey(obj, section_name, key_name, key_value, value_formats)
%addKey - add key in a end given section
[inds, count_keys] = obj.getKeysIndexes(section_name);
[status, write_value] = obj.insertKey(section_name, ...
count_keys+1, key_name, key_value, value_formats);
end
%------------------------------------------------------------------
function [status, set_status] = ...
insertKey(obj, section_name, key_pos, key_name, key_value, value_formats)
%insertKey - insert key into the specified position in a given section
CheckIsScalarPositiveInteger(key_pos);
set_status = false;
key_name = obj.validateKeyName(key_name);
sect_num = obj.nameToNumSection(section_name);
if (~isempty(sect_num) && ~isempty(key_name))
is_unique_key = obj.isUniqueKeyName(section_name, key_name);
if ~is_unique_key
status = false;
return;
end
[key_indicies, count_keys] = obj.getKeysIndexes(section_name);
if (count_keys > 0)
if (key_pos <= count_keys)
insert_index = key_indicies(key_pos);
elseif (key_pos > count_keys)
insert_index = key_indicies(end) + 1;
end
else
insert_index = obj.indicies_of_sections(sect_num) + 1;
end
new_data = {key_name, '', ''};
obj.config_data_array = InsertCell(obj.config_data_array, ...
insert_index, new_data);
obj.updateCountStrings();
obj.updateSectionsInfo();
obj.updateEmptyStringsInfo();
obj.updateCountKeysInfo();
if ~isempty(key_value)
set_status = obj.setValue(section_name, key_name, ...
key_value, value_formats);
end
status = true;
else
status = false;
end
end
%------------------------------------------------------------------
function status = removeKey(obj, section_name, key_name)
%removeKey - remove the key from a given section
key_name = obj.validateKeyName(key_name);
sect_num = obj.nameToNumSection(section_name);
[keys, count_keys] = obj.getKeys(section_name);
if (~isempty(sect_num) && ~isempty(key_name) && count_keys > 0)
is_unique_key = obj.isUniqueKeyName(section_name, key_name);
if is_unique_key
status = false;
return;
end
status = find(strcmp(key_name, keys), 1, 'last');
key_indicies = obj.getKeysIndexes(section_name);
key_index = key_indicies(status);
obj.config_data_array(key_index, :) = [];
obj.updateCountStrings();
obj.updateSectionsInfo();
obj.updateEmptyStringsInfo();
obj.updateCountKeysInfo();
status = true;
else
status = false;
end
end
%------------------------------------------------------------------
function status = renameKey(obj, section_name, old_key_name, new_key_name)
%renameKey - rename the key in a given section
old_key_name = obj.validateKeyName(old_key_name);
new_key_name = obj.validateKeyName(new_key_name);
sect_num = obj.nameToNumSection(section_name);
[keys, count_keys] = obj.getKeys(section_name);
if (~isempty(sect_num) && ~isempty(old_key_name) && ...
~isempty(new_key_name) && count_keys > 0)
is_unique_key = obj.isUniqueKeyName(section_name, old_key_name);
if is_unique_key
status = false;
return;
end
status = find(strcmp(old_key_name, keys), 1, 'last');
key_indicies = obj.getKeysIndexes(section_name);
key_index = key_indicies(status);
obj.config_data_array{key_index, 1} = new_key_name;
status = true;
else
status = false;
end
end
%------------------------------------------------------------------
function status = setValue(obj, section_name, key_name, key_value, value_format)
%setValue
key_name = obj.validateKeyName(key_name);
if ~obj.isSection(section_name)
status = false;
return;
end
if ~obj.isKey(section_name, key_name)
status = false;
return;
end
key_index = obj.getKeyIndex(section_name, key_name);
if isempty(value_format)
str_value = num2str(key_value);
else
value_format = ValidateValueFormat(value_format);
str_value = num2str(key_value, value_format);
end
if (isvector(key_value) && isnumeric(key_value))
str_value = CorrectionNumericArrayStrings(str_value);
end
obj.config_data_array(key_index, 2) = {str_value};
status = true;
end
%------------------------------------------------------------------
function [key_value, status] = getValue(obj, ...
section_name, key_name, default_value)
%getValue - get key value
status = false;
if ~obj.isSection(section_name)
key_value = default_value;
return;
end
if ~obj.isKey(section_name, key_name)
key_value = default_value;
return;
end
key_index = obj.getKeyIndex(section_name, key_name);
str_value = obj.config_data_array{key_index, 2};
key_value = ParseValue(str_value);
status = true;
end
%------------------------------------------------------------------
function [key_names, count_keys] = getKeys(obj, section_name)
%getKeys
[key_indicies, count_keys] = obj.getKeysIndexes(section_name);
if ~isempty(key_indicies)
key_names = obj.config_data_array(key_indicies, 1);
else
key_names = {};
end
end
end % private methods
%----------------------------------------------------------------------
end % classdef IniConfig
%--------------------------------------------------------------------------
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Tools Functions
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%==========================================================================
function [file_data, status] = GetDataFromFile(file_name)
%GetDataFromFile - Get data from file
fid = fopen(file_name, 'r');
if (fid ~= -1)
file_data = textscan(fid, ...
'%s', ...
'delimiter', '\n', ...
'endOfLine', '\r\n');
fclose(fid);
status = true;
file_data = file_data{1};
else
status = false;
file_data = {};
end
end
%--------------------------------------------------------------------------
%==========================================================================
function config_data = ParseConfigData(file_data, comment_style)
%ParseConfigData - parse data from the INI file
% Select the comment in a separate array
pat = sprintf('^[^%s]+', comment_style);
comment_data = regexprep(file_data, pat, '');
% Deleting comments
pat = sprintf('%s.*+$', comment_style);
file_data = regexprep(file_data, pat, '');
% Select the key value in a separate array
values_data = regexprep(file_data, '^.[^=]*.', '');
% Select the names of the sections and keys in a separate array
keys_data = regexprep(file_data, '=.*$', '');
config_data = cell(size(file_data, 1), 3);
config_data(:,1) = keys_data;
config_data(:,2) = values_data;
config_data(:,3) = comment_data;
config_data = strtrim(config_data);
end
%--------------------------------------------------------------------------
%==========================================================================
function value = ParseValue(value)
%ParseValue - classify the data types and convert them
% , value
start_idx = regexp(value, '[^\.\s-+,0-9ij]', 'once');
if ~isempty(start_idx)
return;
end
num = StringToNumeric(value);
if ~isnan(num)
value = num;
end
end
%--------------------------------------------------------------------------
%==========================================================================
function num = StringToNumeric(str)
%StringToNumeric - convert string to numeric data
if isempty(str)
num = NaN;
return;
end
delimiter = ',';
str = regexprep(str, '\s*,*\s*', delimiter);
cells = textscan(str, '%s', 'delimiter', delimiter);
cells = cells{:}';
num_cell = cellfun(@(x) str2double(x), cells, 'UniformOutput', false);
is_nans = cellfun(@(x) isnan(x), num_cell, 'UniformOutput', true);
if any(is_nans)
num = NaN;
else
num = cell2mat(num_cell);
end
end
%--------------------------------------------------------------------------
%==========================================================================
function values = CorrectionNumericArrayStrings(values)
%CorrectionNumericArrayStrings - correction strings of numeric arrays
values = regexprep(values, '\s+', ', ');
end
%--------------------------------------------------------------------------
%==========================================================================
function comment_style = ValidateCommentStyle(comment_style)
%ValidateCommentStyle - validate style of comments
if ~ischar(comment_style)
error('Requires char input for comment style.')
end
end
%--------------------------------------------------------------------------
%==========================================================================
function key_values = ValidateValues(key_values)
%ValidateValues - validate data of key values
is_valid = cellfun(@(x) ...
(isempty(x) | ischar(x) | (isnumeric(x) & isvector(x))), ...
key_values, 'UniformOutput', true);
if ~all(is_valid)
error('Invalid type of one or more <%s>.', inputname(key_values));
end
% transform key_values to vector-rows
key_values = cellfun(@(x) x(:).', key_values, 'UniformOutput', 0);
end
%--------------------------------------------------------------------------
%==========================================================================
function value_format = ValidateValueFormat(value_format)
%ValidateValueFormat -
CheckIsString(value_format);
value_format = strtrim(value_format);
valid_formats = 'd|i|u|f|e|g|E|G';
start_ind = regexp(value_format, ...
['^%\d*\.?\d*(', valid_formats, ')$'], 'once');
if isempty(start_ind)
error('Invalid value format "%s".', value_format)
end
value_format = strrep(value_format, '%', '% ');
end
%--------------------------------------------------------------------------
%==========================================================================
function CheckEqualNumberElems(input1, input2)
%CheckEqualNumberElems - checking equal numbers of elements
if (numel(input1) ~= numel(input2))
error(['Number of elements in the <%s> and ', ...
'<%s> must be equal.'], inputname(1), inputname(2))
end
end
%--------------------------------------------------------------------------
%==========================================================================
function CheckIsString(input_var)
%CheckIsString
if ~(ischar(input_var) && isvector(input_var))
error('<%s> must be a string.', inputname(1))
end
end
%--------------------------------------------------------------------------
%==========================================================================
function CheckIsScalarPositiveInteger(input_var)
%CheckIsScalarPositiveInteger
if ~(isscalar(input_var) && isnumeric(input_var))
error('<%s> must be a scalar.', inputname(1))
end
if (input_var < 1)
error('<%s> must be a positive integer > 0.', inputname(1))
end
end
%--------------------------------------------------------------------------
%==========================================================================
function cell_data = PadDataToCell(data, number_elems)
%PadDataToCell - pad data to cell array
cell_data = {data};
cell_data = cell_data(ones(1, number_elems), :);
end
%--------------------------------------------------------------------------
%==========================================================================
function data_var = DataToCell(data_var)
%DataToCell - convert data to cell array
if ~iscell(data_var)
data_var = {data_var};
else
data_var = data_var(:);
end
end
%--------------------------------------------------------------------------
%==========================================================================
function B = InsertCell(C, i, D)
%InsertCell - insert a new cell or several cells in a two-dimensional
% array of cells on the index
B = [C(1:i-1, :); D; C(i:end, :)];
end
%--------------------------------------------------------------------------