📄 bvqxinifile.m
字号:
function [varargout] = BVQXinifile(varargin)
% BVQXinifile (class)
%
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Version: v0.7b
% Build: 7090311
% Date: Sep-03 2007, 11:17 AM CEST
% Author: Jochen Weber, Brain Innovation, B.V., Maastricht, NL
% URL / Info: http://wiki.brainvoyager.com/BVQXtools
%
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% creates an object for ini-file handling
%
% Input: for meaningful object construction, give filename!
%
% ___ Constructor methods: ___
% ----------------------------
%
% BVQXinifile returns a handle to an BVQXinifile object
% FORMAT: IniFileObject = BVQXinifile(Filename [,convert]);
% FORMAT: NewObject = BVQXinifile('convert' | 'new');
% FORMAT: FactoryObject = BVQXinifile;
%
% ReleaseAllFiles issue release for all open objects
% ReloadAllFiles issue reload for all open objects
% ResetClass resets the internal variable, useful for debugging
% SetIniString create an IniFile object from an inistring
%
% ___ NOTES: ___
% --------------
%
% *) with conversion active, BVQXinifile uses any2ascii, another part
% of this toolbox to write non-character variables to disk;
% when not active, only valid one-line char arrays are allowed!
%
% **) storage for the ini file settings is NOT part of the object, but
% is requested and maintained by the singleton object itself, thus
% only little memory is needed for argument handling, even with
% bigger ini file, plus multiple functions can share one ini file!
% persistent storage for BVQXinifile object and factory variables
persistent bvqxinic;
persistent bvqxinif;
% bvqxinic internal object with subfields
% .caller who opened this file initially
% .children internal list of file-IDs that depend on this file
% .convert is the content converted (evaled/hxdouble'd)
% .filename holds the filename (or a temporary name)
% .icontent content of the file as struct representation
% .parent either empty or internal file-ID of parent file
% .postfile string of characters after terminating sequence
% .prefile string of characters before first section
% .readwrite single character option for write protection,
% whereas 'a' stands for all, 'c' for caller,
% 'm' for memory-only, and 'n' for no write access
%
% bvqxinif factory object with subfields
% .fterm ini-file terminator
% .is_init initialization complete flag
% .lineout configurable line break character sequence
% .matrix ID lookup table
% .raction read-only actions
% .uaction list of actions that don't need a valid ID
% .waction write-file actions
% check for class initialization -> do if necessary
if isempty(bvqxinif) || ...
~bvqxinif.is_init
% configuration settings
bvqxinif.fterm = '[/EndOfBVQXinifile]';
bvqxinif.is_init = false;
bvqxinif.lineout = char(10);
bvqxinif.matrix = [];
% array of read-only actions for protection scheme
bvqxinif.raction = struct( ...
'display', true, ...
'getcaller', true, ...
'getchildren', true, ...
'getcomplete', true, ...
'getfilename', true, ...
'getfoot', true, ...
'gethead', true, ...
'getid', true, ...
'getinisection', true, ...
'getinisetting', true, ...
'getinistring', true, ...
'getparents', true, ...
'getprotection', true, ...
'getsections', true, ...
'getsectionsettings', true, ...
'issection', true, ...
'issetting', true, ...
'isvalid', true ...
);
% array of available actions for calls with object ID = 0
bvqxinif.uaction = struct( ...
'display', true, ...
'isvalid', true, ...
'loadinifile', true, ...
'newinifile', true, ...
'parseinistring', true, ...
'releaseallfiles', true, ...
'reloadallfiles', true, ...
'resetclass', true ...
);
% array of file-write actions for protection scheme
bvqxinif.waction = struct( ...
'saveinifile', true, ...
'saveinifileas', true ...
);
% initialize object structure
bvqxinic = struct( ...
'caller' , '', ...
'children' , [], ...
'convert' , 0, ...
'filename' , '', ...
'icontent' , struct, ...
'parent' , [], ...
'postfile' , '', ...
'prefile' , '', ...
'readwrite', 'a' ...
);
% set initialization successful to true
bvqxinif.is_init = true;
% and get factory handle
bvqxinif.xhfactory = class(struct('L', 0), 'BVQXinifile');
end
hf = bvqxinif.xhfactory;
% if no arguments given return factory
if nargin < 1
% initialize basic return object and return
varargout{1} = hf;
return;
end
% input argument check
if nargin < 3 && ...
~isa(varargin{1}, 'BVQXinifile')
% first is string
if ischar(varargin{1}) && ...
~isempty(varargin{1})
% but no filename...
if exist(varargin{1}(:)','file') ~= 2
% if it is neither 'convert', 'exact', or 'new'
if ~any(strcmpi(varargin{1}(:)', {'convert', 'exact', 'new'}))
error( ...
'BVQXinifile:FileNotFound', ...
'The specified file wasn''t found.' ...
);
% assume NewIniFile constructor meaning
else
varargout{1} = ...
BVQXinifile(hf, 'newinifile', lower(varargin{1}(:)'));
return;
end
end
% perform filename call
varargout{1} = BVQXinifile(hf, 'loadinifile', varargin{:});
return;
% if we get a numeric argument...
elseif isa(varargin{1}, 'double') && ...
numel(varargin{1}) == 1
% is an object in list
if any(bvqxinif.matrix == varargin{1})
varargout{1} = class(struct('L', varargin{1}), 'BVQXinifile');
return;
% give an error otherwise
else
error( ...
'BVQXinifile:InvalidFileID', ...
'The given ID wasn''t found in the lookup matrix.' ...
);
end
end
% otherwise bark out if first argument in NOT an BVQXinifile object
elseif ~isa(varargin{1}, 'BVQXinifile') || ...
numel(varargin{1}) ~= 1 || ...
nargin < 2 || ...
~ischar(varargin{2})
error( ...
'BVQXinifile:CallingConvention', ...
'Illegal call to BVQXinifile.' ...
);
end
hIniFile = varargin{1};
action = lower(varargin{2}(:)');
varargout{1} = hIniFile;
% get ID and look up the matrix position of file...
cfid = hIniFile.L;
if cfid ~= 0
cfid = find(bvqxinif.matrix == cfid);
if isempty(cfid)
if ~strcmp(action, 'isvalid')
error( ...
'BVQXinifile:InvalidFileID', ...
'File lookup error. Possible programming error?' ...
);
else
varargout{1} = false;
return;
end
end
end
% disallow all actions that do need a "vadid" ID
if ~isfield(bvqxinif.uaction, action) && ...
cfid == 0
error( ...
'BVQXinifile:InvalidAction', ...
'The requested action needs a valid object to work.' ...
);
end
% get current object
if cfid > 0
cfile = bvqxinic(cfid);
% check protection first
switch cfile.readwrite
% only caller
case {'c'}
% test caller / action pair
ncaller = extcaller(1);
ocaller = cfile.caller;
if ~isfield(bvqxinif.raction, action) && ...
~strcmp(ncaller, ocaller)
warning( ...
'BVQXinifile:ProtectionViolation', ...
'The object has ''caller-only'' write access.' ...
);
return;
end
% file protection only
case {'m'}
% test for writefile action strings
if isfield(bvqxinif.waction, action)
warning( ...
'BVQXinifile:ProtectionViolation', ...
'The object has ''memory-only'' write access.' ...
);
return;
end
% no write access at all
case {'n'}
% test for read-only action string
if ~isfield(bvqxinif.raction, action)
warning( ...
'BVQXinifile:ProtectionViolation', ...
'The object has write access disabled.' ...
);
return;
end
end
end
% switch over action
switch (action)
% display (also used for writing!)
case {'display'}
% initialize output variable
lineout = bvqxinif.lineout;
dispout = '';
filepost = '';
indent = ' ';
equalchar = ' = ';
% if we have a valid object ID (other than the factory)
if cfid > 0
% get conversion state
tconvert = cfile.convert;
issave = false;
% if we're going to write the file to disk reset some vars!
if nargin > 2 && ...
ischar(varargin{3}) && ...
strcmpi(varargin{3}(:)', 'saveinifile')
dispout = cfile.prefile(:)';
filepost = cfile.postfile(:)';
indent = '';
equalchar = '=';
lineout = char([13, 10]);
issave = true;
% make sure to add correct footer if is invalid or empty
if ~ischar(filepost) || ...
numel(filepost) < 1
filepost = [bvqxinif.fterm lineout];
end
% do we have a correct footer now?
hasend = strfind(filepost,bvqxinif.fterm);
if isempty(hasend)
filepost = [bvqxinif.fterm lineout filepost];
% remove any leading chars before good terminator
elseif hasend(1) ~= 1
filepost(1:(hasend(1)-1)) = [];
end
end
% correctly terminate header and footer
if numel(dispout) > 0 && ...
dispout(end) ~= char(10) && ...
dispout(end) ~= char(13)
dispout = [dispout lineout];
end
if numel(filepost) > 0 && ...
filepost(end) ~= char(10) && ...
filepost(end) ~= char(13)
filepost = [filepost lineout];
end
% iterate over sections
cfs = fieldnames(cfile.icontent);
for sectcount = 1:numel(cfs)
% initialize section output
sdispout = '';
extralarge = {};
% get section name and content, and add name to dispout
sectname = cfs{sectcount};
csection = cfile.icontent.(cfs{sectcount});
sdispout = [sdispout '[' sectname ']' lineout];
% re-set non-structs
if ~isstruct(csection)
if ~iscell(csection)
csection = struct('Value', csection);
else
csection = struct('Value', {csection});
end
end
% iterate over settings in section
namsettings = fieldnames(csection);
for namecount = 1:numel(namsettings)
% get value for setting
fvalue = csection.(namsettings{namecount});
% do we have non character, invalid characters or not 1xN
if tconvert < 1 && ...
(~ischar(fvalue) || ...
any(fvalue < 32 | fvalue > 127) || ...
size(fvalue, 1) > 1 || ...
ndims(fvalue) > 2)
if issave
error( ...
'BVQXinifile:BadSettingValue', ...
'Bad value for %s.%s (no conversion).', ...
sectname, ...
namsettings{namecount} ...
);
else
warning( ...
'BVQXinifile:BadSettingValue', ...
'Bad value for %s.%s (no conversion).', ...
sectname, ...
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -