Files
2023-08-10 09:19:49 +02:00

1245 lines
48 KiB
Matlab

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.
%
%
% 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)
% ---------------------------------------------------------------------
%
% Support data types:
% * numeric scalars and vectors
% * logical scalars and vectors
% * strings
%
% ---------------------------------------------------------------------
%
% Using:
% ini = IniConfig(); % Constructor (an instance of class)
%
% 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
%
% ---------------------------------------------------------------------
%
% Example:
% ini = IniConfig();
% ini.ReadFile('example.ini')
% sections = ini.GetSections()
% [keys, count_keys] = ini.GetKeys(sections{1})
% values = ini.GetValues(sections{1}, keys, cell(count_keys, 1))
% new_values = cell(count_keys, 1);
% new_values(:) = {rand()};
% ini.SetValues(sections{1}, keys, new_values)
% ini.WriteFile('example1.ini')
%
%
% Example:
% ini = IniConfig();
% ini.AddSection('Some Section 1')
% ini.AddKey('Some Section 1', 'some_key1', 'hello!')
% ini.AddKey('Some Section 1', 'some_key2', [10, 20])
% ini.AddKey('Some Section 1', 'some_key3', true)
% ini.AddSection('Some Section 2')
% ini.AddKey('Some Section 2', 'some_key1')
% ini.WriteFile('example2.ini')
%
%
% Example:
% ini = IniConfig();
% ini.AddSection('Some Section 1')
% ini.AddKey('Some Section 1', 'some_key1', 'hello!')
% ini.AddKey('Some Section 1', 'some_key2', [10, 20])
% ini.AddKey('Some Section 1', 'some_key3', [false, true])
% ini.WriteFile('example31.ini')
% ini.RemoveKey('Some Section 1', 'some_key1')
% ini.RenameKey('Some Section 1', 'some_key2', 'renamed_some_key2')
% ini.RenameSection('Some Section 1', 'Renamed Section 1')
% ini.WriteFile('example32.ini')
%
%
% ---------------------------------------------------------------------
% Note:
% This implementation does not use cycles, and works fairly quickly,
% even on large files.
% Parsing the files by using regular expressions
% All comments are saved when set values
%
% This class was tested on the win32 platform only but it should
% also work on Unix/Linux platforms.
%
%
% ---------------------------------------------------------------------
% Author: Iroln <iroln85@gmail.com>
% Version: 0.6.2
% First release: 25.07.09
% Last revision: 11.08.09
% Copyright: (c) 2009 Evgeny Pr aka Iroln. All rights reserved.
%
% Bug reports, questions, etc. can be sent to the e-mail given above.
% ---------------------------------------------------------------------
properties (GetAccess = 'public', SetAccess = 'private')
comment_style = ';'
count_sections = 0
full_count_keys = 0
end
properties (GetAccess = 'private', SetAccess = 'private')
file_name = ''
config_data_array = {}
indexes_of_sections = []
indexes_of_empty_str = []
count_strings = 0
count_empty_strings = 0
is_created_configuration = false
end
methods
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Public Methods
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%------------------------------------------------------------------
function obj = IniConfig()
%IniConfig - Constructor
% To Create empty default configuration.
% Using:
% ini_obj = IniConfig()
%
obj.CreateIni();
end
%------------------------------------------------------------------
function status = ReadStream(obj, data_stream, comment_style)
obj.comment_style = ValidateCommentStyle(comment_style);
file_data = data_stream;
obj.count_strings = size(file_data, 1);
% Parse data
obj.config_data_array = IniFileParser(file_data, obj.comment_style);
obj.UpdateSectionsInfo()
obj.UpdateEmptyStringsInfo()
obj.UpdateCountKeysInfo()
obj.is_created_configuration = true;
end
%------------------------------------------------------------------
function status = ReadFile(obj, filename, comment_style)
%ReadFile - to read in the object the config data from a INI file
% Using:
% status = ReadFile(filename, comment_style)
% status - 1 (true): Success
% status - 0 (false): Failed
%
if (nargin < 2)
error('Not enough input arguments.')
elseif (nargin == 3)
obj.comment_style = ValidateCommentStyle(comment_style);
end
if ~ischar(filename)
error('Requires string input.')
else
% Get data from file
fid = fopen(filename, 'r');
if (fid ~= -1)
file_data = textscan(fid, ...
'%s', ...
'delimiter', '\n', ...
'endOfLine', '\r\n');
fclose(fid);
status = true;
else
status = false;
return;
end
obj.file_name = filename;
file_data = file_data{1};
obj.count_strings = size(file_data, 1);
% Parse data
obj.config_data_array = IniFileParser(file_data, obj.comment_style);
obj.UpdateSectionsInfo()
obj.UpdateEmptyStringsInfo()
obj.UpdateCountKeysInfo()
obj.is_created_configuration = true;
end
end
%------------------------------------------------------------------
function status = IsSection(obj, section_name)
%IsSection - determine whether there is a section
% Using:
% status = IsSection(section_name)
% status - 1 (true): section is found
% status - 0 (false): section is not found
%
if (obj.is_created_configuration)
if (nargin < 2)
error('Not enough input arguments.')
end
section_name = obj.ValidateSectionName(section_name);
sect_num = obj.NameToNumSection(section_name);
if ~isempty(sect_num)
status = ~obj.IsUniqueSectionName(section_name);
else
status = false;
end
else
error('Configuration is not created or not loaded.')
end
end
%------------------------------------------------------------------
function status = IsKey(obj, section_name, key_name)
%IsSection - determine whether there is a key in a given section
% Using:
% status = IsKey(section_name, key_name)
% status - 1 (true): key is found
% status - 0 (false): key is not found
%
if (obj.is_created_configuration)
if (nargin < 3)
error('Not enough input arguments.')
end
section_name = obj.ValidateSectionName(section_name);
key_name = obj.ValidateKeyName(key_name);
sect_num = obj.NameToNumSection(section_name);
if (~isempty(sect_num) && ~isempty(key_name))
status = ~obj.IsUniqueKeyName(section_name, key_name);
else
status = false;
end
else
error('Configuration is not created or not loaded.')
end
end
%------------------------------------------------------------------
function [names_sect, count_sect] = GetSections(obj)
%GetSections - get names of all sections
% Using:
% [names_sect, count_sect] = GetSections()
%
% Output:
% names_sect - cell array with the names of sections
% count_sect - number of sections in configuration
%
if (obj.is_created_configuration)
names_sect = obj.config_data_array(obj.indexes_of_sections, 1);
count_sect = obj.count_sections;
else
error('Configuration is not created or not loaded.')
end
end
%------------------------------------------------------------------
function [keys_names, count_keys] = GetKeys(obj, section_name)
%GetKeys - get names of all keys from given section
% Using:
% [keys_names, count_keys] = GetKeys(section_name)
%
% Output:
% keys_names - cell array with the names of keys
% count_keys - number of keys in given section
%
if (obj.is_created_configuration)
if (nargin < 2)
error('Not enough input arguments.')
end
section_name = obj.ValidateSectionName(section_name);
[keys_indexes, count_keys] = obj.GetKeysIndexes(section_name);
if isempty(keys_indexes)
keys_names = {};
count_keys = 0;
return;
end
keys_names = obj.config_data_array(keys_indexes, 1);
else
error('Configuration is not created or not loaded.')
end
end
%------------------------------------------------------------------
function [values, count_read] = GetValues(obj, section_name, keys_names, default_values, param_name, param_val)
%GetValues - get values of keys from given section
% Using:
% [values, count_read] = GetValues(section_name, ...
% keys_names, ...
% default_values, ...
% param_name, ...
% param_val)
% Output:
% values - cell array with the values
% count_read - number of successfully get values
%
% Input:
% section_name - name of given section
% keys_names - names of given keys
% default_values - default values
%
% Optional Input Parameters:
% param_name - must be 'AlwaysReturnCell'
% param_val - must be 0 or 1
%
if (obj.is_created_configuration)
if (nargin < 4)
error('Not enough input arguments.')
elseif (nargin == 4)
is_get_values_always_in_cell = true;
elseif (nargin == 5)
error('Not enough input arguments.')
elseif (nargin == 6)
if ischar(param_name)
if strcmpi('AlwaysReturnCell', param_name)
if (param_val == 0 || param_val == 1)
is_get_values_always_in_cell = logical(param_val);
else
error('Value must be 0 or 1.')
end
else
error('Invalid param name: "%s". Must be "AlwaysReturnCell"', param_name)
end
else
error('The method GetValue expects a string "AlwaysReturnCell".')
end
end
section_name = obj.ValidateSectionName(section_name);
[keys_names, default_values] = ...
ValidateInputsForGetAndSetValues(section_name, ...
keys_names, default_values);
count_keys = numel(keys_names);
values = cell(count_keys, 1);
count_read = 0;
keys_indexes = obj.GetKeysIndexes(section_name);
if isempty(keys_indexes)
values = default_values;
if (length(values) == 1 && ~is_get_values_always_in_cell)
values = values{1};
end
return;
end
keys_names = strtrim(keys_names);
keys = obj.config_data_array(keys_indexes, 1);
vals = obj.config_data_array(keys_indexes, 2);
% Get the names of keys, which are not in the INI file
% in a given section and specifying this key Defaults
[not_found_keys, not_found_indexes] = setdiff(keys_names, keys);
values(not_found_indexes) = default_values(not_found_indexes);
% Getting the names of keys, which is in the INI file in a
% given section
[found_keys, found_indexes, found_data_indexes] = intersect(keys_names, keys);
values(found_indexes) = vals(found_data_indexes);
count_read = length(found_indexes);
%DEBUG: found_indexes = sort(found_indexes);
values(found_indexes) = ParserValues(values(found_indexes));
if (length(values) == 1 && ~is_get_values_always_in_cell)
values = values{1};
end
else
error('Configuration is not created or not loaded.')
end
end
%------------------------------------------------------------------
function count_write = SetValues(obj, section_name, keys_names, values)
%SetValues - set values for given keys from given section
% Using:
% count_write = SetValues(section_name, keys_names, values)
%
% Output:
% count_write - number of successfully set values
%
% Input:
% section_name - name of given section (must be string)
% keys_names - names of given keys (must be cell array of strings or string)
% values - values of keys (must be cell array or one value)
%
% Note:
% Number of elements in the second and third input argument must be equal
%
if (obj.is_created_configuration)
if (nargin < 4)
error('Not enough input arguments.')
end
section_name = obj.ValidateSectionName(section_name);
[keys_names, values] = ...
ValidateInputsForGetAndSetValues(section_name, ...
keys_names, values);
count_keys = numel(keys_names);
count_write = 0;
keys_indexes = obj.GetKeysIndexes(section_name);
if isempty(keys_indexes)
return;
end
[valid_keys, count_valid_keys] = obj.GetKeys(section_name);
if (count_keys > count_valid_keys)
values = values(1:count_valid_keys);
end
keys_names = strtrim(keys_names);
keys = obj.config_data_array(keys_indexes, 1);
% If the key is not unique within the section, it will be
% processed by the key, which is located the last
[keys_names, m] = unique(keys_names);
values = values(m);
[not_found_keys, not_found_indexes] = setdiff(keys_names, keys);
keys_names(not_found_indexes) = [];
values(not_found_indexes) = [];
[found_keys, found_indexes, found_data_indexes] = intersect(keys_names, keys);
values(sort(found_indexes)) = values(found_indexes);
% Get string value indices
str_indexes = cellfun(@(x) ischar(x), values);
% Get numeric value indices
num_indexes = cellfun(@(x) isnumeric(x), values);
% Get logical value indices
log_indexes = cellfun(@(x) islogical(x), values);
values(num_indexes | log_indexes) = cellfun(@(x) mat2str(x), ...
values(num_indexes | log_indexes), 'UniformOutput', 0);
values(~str_indexes & ~num_indexes & ~log_indexes) = [];
values(str_indexes) = strtrim(values(str_indexes));
values(num_indexes | log_indexes) = ...
CorrectNumArrayStrings(values(num_indexes | log_indexes));
if isempty(values)
values = {''};
end
obj.config_data_array(keys_indexes(found_data_indexes), 2) = values;
count_write = length(values);
else
error('Configuration is not created or not loaded.')
end
end
%------------------------------------------------------------------
function CreateIni(obj)
%CreateIni - create new empty INI configuration
% Using:
% CreateIni()
%
obj.config_data_array = cell(2,3);
obj.config_data_array(:,:) = {''};
obj.UpdateCountStrings();
obj.UpdateSectionsInfo()
obj.UpdateEmptyStringsInfo()
obj.file_name = '';
obj.is_created_configuration = true;
end
%------------------------------------------------------------------
function status = AddSection(obj, section_name)
%AddSection - add section to end configuration
% Using:
% status = AddSection(section_name)
% status - 1 (true): Success
% status - 0 (false): Failed
%
if (obj.is_created_configuration)
if (nargin < 2)
error('Not enough input arguments.')
end
section_name = obj.ValidateSectionName(section_name);
status = obj.InsertSection(obj.count_sections+1, section_name);
else
error('Configuration is not created or not loaded.')
end
end
%------------------------------------------------------------------
function status = InsertSection(obj, pos, section_name)
%InsertSection - insert section to given position
% Using:
% status = InsertSection(pos, section_name)
% status - 1 (true): Success
% status - 0 (false): Failed
%
if (obj.is_created_configuration)
if (nargin < 3)
error('Not enough input arguments.')
else
if (~isnumeric(pos) && ~isscalar(pos))
error('Position must be a scalar positive integer')
end
if (pos < 1)
error('Position must be a positive integer')
elseif (pos > obj.count_sections+1)
pos = obj.count_sections+1;
end
end
section_name = obj.ValidateSectionName(section_name);
if ~isempty(section_name)
is_unique_sect = obj.IsUniqueSectionName(section_name);
if ~is_unique_sect
status = false;
return;
end
if (pos <= obj.count_sections && obj.count_sections > 0)
sect_ind = obj.indexes_of_sections(pos);
elseif (pos == 1 && obj.count_sections == 0)
sect_ind = 1;
obj.config_data_array = {};
elseif (pos == obj.count_sections+1)
%FIXME:
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
else
error('Configuration is not created or not loaded.')
end
end
%------------------------------------------------------------------
function status = RemoveSection(obj, section_name)
%RemoveSection - remove given section
% Using:
% status = RemoveSection(section_name)
% status - 1 (true): Success
% status - 0 (false): Failed
%
if (obj.is_created_configuration)
if (nargin < 2)
error('Not enough input arguments.')
end
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.indexes_of_sections(sect_num);
last_ind = obj.indexes_of_sections(sect_num+1)-1;
elseif (sect_num == obj.count_sections)
first_ind = obj.indexes_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
else
error('Configuration is not created or not loaded.')
end
end
%------------------------------------------------------------------
function status = RenameSection(obj, section_name, new_section_name)
%RenameSection - rename given section
% Using:
% status = RenameSection(section_name, new_section_name)
% status - 1 (true): Success
% status - 0 (false): Failed
%
if (obj.is_created_configuration)
if (nargin < 3)
error('Not enough input arguments.')
end
section_name = obj.ValidateSectionName(section_name);
new_section_name = obj.ValidateSectionName(new_section_name);
sect_num = obj.NameToNumSection(section_name);
if (~isempty(new_section_name) && ~isempty(sect_num))
sect_ind = obj.indexes_of_sections(sect_num);
obj.config_data_array(sect_ind, 1) = {new_section_name};
status = true;
else
status = false;
end
else
error('Configuration is not created or not loaded.')
end
end
%------------------------------------------------------------------
function [status, write_value] = AddKey(obj, section_name, key_name, value)
%AddKey - add key in a end given section
% Using:
% [status, write_value] = AddKey(section_name, key_name, value)
%
% Output:
% status - 1 (true): Success, status - 0 (false): Failed
% write_value - 1 (true): Success, status - 0 (false): Failed
%
if (obj.is_created_configuration)
if (nargin < 3)
error('Not enough input arguments.')
elseif (nargin == 3)
value = '';
end
section_name = obj.ValidateSectionName(section_name);
[keys_indexes, count_keys] = obj.GetKeysIndexes(section_name);
[status, write_value] = obj.InsertKey(section_name, count_keys+1, key_name, value);
else
error('Configuration is not created or not loaded.')
end
end
%------------------------------------------------------------------
function [status, write_value] = InsertKey(obj, section_name, key_pos, key_name, value)
%InsertKey - insert key into the specified position in a given section
% Using:
% [status, write_value] = InsertKey(section_name, key_pos, key_name, value)
%
% Output:
% status - 1 (true): Success, status - 0 (false): Failed
% write_value - 1 (true): Success, status - 0 (false): Failed
%
if (obj.is_created_configuration)
if (nargin < 4)
error('Not enough input arguments.')
elseif (nargin == 4)
value = '';
elseif (nargin == 5)
if isempty(value)
value = '';
end
end
if (~isnumeric(key_pos) && ~isscalar(key_pos))
error('Index must be a scalar positive integer')
else
if (key_pos < 1)
error('Index must be a positive integer')
end
end
write_value = 0;
section_name = obj.ValidateSectionName(section_name);
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
[keys_indexes, count_keys] = obj.GetKeysIndexes(section_name);
if (count_keys > 0)
if (key_pos <= count_keys)
insert_index = keys_indexes(key_pos);
elseif (key_pos > count_keys)
insert_index = keys_indexes(end)+1;
end
else
insert_index = obj.indexes_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(value)
write_value = obj.SetValues(section_name, key_name, value);
end
status = true;
else
status = false;
end
else
error('Configuration is not created or not loaded.')
end
end
%------------------------------------------------------------------
function status = RenameKey(obj, section_name, key_name, new_key_name)
%RenameKey - rename the key in a given section
% Using:
% status = RenameKey(section_name, key_name, new_key_name)
% status - 1 (true): Success
% status - 0 (false): Failed
%
if (obj.is_created_configuration)
if (nargin < 4)
error('Not enough input arguments.')
end
section_name = obj.ValidateSectionName(section_name);
key_name = obj.ValidateKeyName(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(key_name) && ~isempty(new_key_name) && count_keys > 0)
is_unique_key = obj.IsUniqueKeyName(section_name, key_name);
if is_unique_key
status = false;
return;
end
tf = find(strcmp(key_name, keys), 1, 'last');
keys_indexes = obj.GetKeysIndexes(section_name);
key_index = keys_indexes(tf);
obj.config_data_array{key_index, 1} = new_key_name;
status = true;
else
status = false;
end
else
error('Configuration is not created or not loaded.')
end
end
%------------------------------------------------------------------
function status = RemoveKey(obj, section_name, key_name)
%RemoveKey - remove the key from a given section
% Using:
% status = RemoveKey(section_name, key_name)
% status - 1 (true): Success
% status - 0 (false): Failed
%
if (obj.is_created_configuration)
if (nargin < 3)
error('Not enough input arguments.')
end
section_name = obj.ValidateSectionName(section_name);
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
tf = find(strcmp(key_name, keys), 1, 'last');
keys_indexes = obj.GetKeysIndexes(section_name);
key_index = keys_indexes(tf);
obj.config_data_array(key_index, :) = [];
obj.UpdateCountStrings();
obj.UpdateSectionsInfo();
obj.UpdateEmptyStringsInfo();
obj.UpdateCountKeysInfo();
status = true;
else
status = false;
end
else
error('Configuration is not created or not loaded.')
end
end
%------------------------------------------------------------------
function status = WriteFile(obj, filename)
%WriteFile - write to the configuration INI file on disk
% Using:
% status = WriteFile(filename)
% status - 1 (true): Success
% status - 0 (false): Failed
%
if (obj.is_created_configuration)
if (nargin < 1)
error('Not enough input arguments.')
else
if ~ischar(filename)
error('Requires string input.')
else
fid = fopen(filename, 'w');
if (fid ~= -1)
count_str = obj.count_strings;
indexes_of_sect = obj.indexes_of_sections;
config_data = obj.config_data_array;
for k = 1:count_str
if isempty(config_data{k,1})
if isempty(config_data{k,3})
fprintf(fid, '\n');
else
comment_str = config_data{k,3};
fprintf(fid, '%s\n', comment_str);
end
elseif ~isempty(indexes_of_sect(indexes_of_sect == k))
if isempty(config_data{k,3})
section_str = config_data{k,1};
fprintf(fid, '%s\n', section_str);
else
section_str = config_data{k,1};
comment_str = config_data{k,3};
fprintf(fid, '%s %s\n', ...
section_str, comment_str);
end
elseif ~isempty(config_data{k,1}) && ...
isempty(indexes_of_sect(indexes_of_sect == k))
if isempty(config_data{k,3})
key_str = config_data{k,1};
val_str = config_data{k,2};
fprintf(fid, '%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};
fprintf(fid, '%s = %s %s\n', ...
key_str, val_str, comment_str);
end
end
end
fclose(fid);
status = true;
else
status = false;
return;
end
end
end
else
error('Configuration is not created or not loaded.')
end
end
end % public methods
methods (Access = 'private')
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Private Methods
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%------------------------------------------------------------------
function num = NameToNumSection(obj, name)
%NameToNumSection - get number of section
sections = obj.GetSections();
indexes = find(strcmp(name, sections));
if ~isempty(indexes)
% If the section is not unique, then choose the latest
num = indexes(end);
else
num = [];
end
end
%------------------------------------------------------------------
function [keys_indexes, count_keys] = GetKeysIndexes(obj, section_name)
%GetKeysIndexes - get keys indices from given section
sect_num = obj.NameToNumSection(section_name);
if isempty(sect_num)
keys_indexes = [];
count_keys = 0;
return;
elseif (sect_num == obj.count_sections)
keys_indexes = ...
obj.indexes_of_sections(sect_num)+1:obj.count_strings;
else
keys_indexes = ...
obj.indexes_of_sections(sect_num)+1:obj.indexes_of_sections(sect_num+1)-1;
end
indexes_of_empty = obj.indexes_of_empty_str;
[i_str, empty_indexes] = intersect(keys_indexes, indexes_of_empty);
keys_indexes(empty_indexes) = [];
keys_indexes = keys_indexes(:);
count_keys = length(keys_indexes);
end
%------------------------------------------------------------------
function UpdateSectionsInfo(obj)
%UpdateSectionsInfo
keys_data = obj.config_data_array(:,1);
sect_indexes_cell = regexp(keys_data, '^\[.*\]$');
obj.indexes_of_sections = find(cellfun(@(x) ~isempty(x), sect_indexes_cell));
obj.count_sections = length(obj.indexes_of_sections);
end
%------------------------------------------------------------------
function UpdateCountKeysInfo(obj)
%UpdateCountKeys
obj.full_count_keys = obj.count_strings - obj.count_sections - obj.count_empty_strings;
end
%------------------------------------------------------------------
function UpdateEmptyStringsInfo(obj)
%UpdateEmptyStringsInfo
keys_data = obj.config_data_array(:,1);
indexes_of_empty_cell = strcmp('', keys_data);
obj.indexes_of_empty_str = find(indexes_of_empty_cell);
obj.count_empty_strings = length(obj.indexes_of_empty_str);
end
%------------------------------------------------------------------
function UpdateCountStrings(obj)
%UpdateCountStrings
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 section_name = ValidateSectionName(obj, section_name)
%ValidateSectionName - check the name of the section
if (~ischar(section_name) || size(section_name, 1) > 1)
error('Requires string input for name of section.')
else
section_name = strtrim(section_name);
if isempty(section_name)
section_name = [];
else
sect_indexes_cell = regexp(section_name, '^\[.*\]$', 'once');
indexes_cell_comment = regexp(section_name, obj.comment_style, 'once');
if ~isempty(indexes_cell_comment)
section_name = [];
return;
end
if isempty(sect_indexes_cell)
section_name = ['[', section_name, ']'];
end
end
end
end
%------------------------------------------------------------------
function key_name = ValidateKeyName(obj, key_name)
%ValidateKeyName - check the name of the key
if (~ischar(key_name) || size(key_name, 1) > 1)
error('Requires string input for key name.')
else
key_name = strtrim(key_name);
indexes_cell = regexp(key_name, '^\[.*\]$', 'once');
indexes_cell_comment = regexp(key_name, obj.comment_style, 'once');
if isempty(key_name) || ~isempty(indexes_cell) || ~isempty(indexes_cell_comment)
key_name = [];
end
end
end
end % private methods
end % classdef IniConfig
%--------------------------------------------------------------------------
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Tools Functions
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%==========================================================================
function config_data = IniFileParser(file_data, comment_style)
%IniFileParser - parser 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 values = ParserValues(values)
%ParserValues - classify the data types and convert them
start_idx = regexp(values, '^[\-\d\s\,\.\:truefalse]+$');
number_indexes = cellfun(@(x) ~isempty(x), start_idx);
num_values_strs = values(number_indexes);
num_values = cellfun(@(x) str2num(x), num_values_strs, 'UniformOutput', 0);
empty_num_indexes = cellfun(@(x) isempty(x), num_values);
num_values(empty_num_indexes) = num_values_strs(empty_num_indexes);
values(number_indexes) = num_values;
empty_indexes = cellfun(@(x) isempty(x), values);
values(empty_indexes) = {[]};
end
%--------------------------------------------------------------------------
%==========================================================================
function values = CorrectNumArrayStrings(values)
%CorrectNumStrings
values = regexprep(values, '^\[', '');
values = regexprep(values, '\]$', '');
values = regexprep(values, '\s', ', ');
end
%--------------------------------------------------------------------------
%==========================================================================
function comment_style = ValidateCommentStyle(comment_style)
%ValidateCommentStyle
if ~ischar(comment_style)
error('Requires char input for comment style.')
else
if (length(comment_style) ~= 1)
error('The style comments should contain the single character')
end
end
end
%--------------------------------------------------------------------------
%==========================================================================
function [keys, values] = ValidateInputsForGetAndSetValues(section, keys, values)
%ValidateInputsForGetAndSetValues
if ~ischar(section)
error('First input argument must be a string.')
end
if ~ischar(keys) && ~iscellstr(keys)
error('Second input argument must be a string or cell array of strings_indexes.')
else
if ischar(keys)
keys = {keys};
end
end
if ~iscell(values)
values = {values};
end
if (numel(keys) ~= numel(values))
error('Number of elements in the second and third input argument must be equal')
end
keys = keys(:);
values = values(:);
end
%--------------------------------------------------------------------------
%==========================================================================
function B = insertcell(C, index, data)
%insertcell - insert a new cell or several cells in a two-dimensional
% array of cells on the index
M = index;
N = 1;
if ~iscell(data)
data = {data};
end
[m, n] = size(C);
[md, nd] = size(data);
mm = m + md;
nt = nd + N - n - 1;
if (nt > 0)
nn = n + nt;
else
nn = n;
end
B = cell(mm, nn);
B(M:M+md-1, N:N+nd-1) = data;
ia = 1:M-1;
ib = M+md:mm;
j = 1:n;
ibb = [ia, ib];
if (m > 2)
t = 0;
else
t = 1;
end
icc = [ia, M:length(C)-t];
B(ibb, j) = C(icc, j);
end
%--------------------------------------------------------------------------