source: ResearchApps/PHY/WARPLAB/WARPLab7/M_Code_Reference/util/inifile/inifile.m

Last change on this file was 1915, checked in by murphpo, 11 years ago

initial commit of WARPLab7 code

File size: 31.3 KB
Line 
1function varargout = inifile(varargin)
2%INIFILE Creates, reads, or writes data from/to a standard ini (ascii)
3%        file. Such a file is organized into sections
4%       ([section name]), subsections(enclosed by {subsection name}),
5%       and keys (key=value).  Empty lines and lines with the first non-empty
6%       character being ; (comment lines) are ignored.
7%
8%   Usage:
9%       INIFILE(fileName,'new')
10%           Rewrites an existing file - creates a new, empty file.
11%
12%       INIFILE(fileName,'write',keys,<style>)
13%           Writes keys given as cell array of strings (see description of
14%           the keys below). Optional style variable: 'tabbed' writes sections,
15%           subsections and keys in a tabbed style to get more readable
16%           file. The 'plain' style is the default style. This only affects
17%           the keys that will be written/rewritten.
18%
19%       INIFILE(fileName,'deletekeys',keys)
20%           Deletes keys and their values - if they exist.
21%
22%       [readsett,result] = INIFILE(fileName,'read',keys)
23%           Reads the values of the keys where readsett is a cell array of
24%           strings and/or numeric values of the keys. If any of the keys
25%           is not found, the default value is returned (if given in the
26%           5-th column of the keys parameter). result is a cell array of
27%           strings - one for each key read; empty if OK, error/warning
28%           string if error; in both cases an empty string is returned in
29%           readsett{i} for the i-th key if error.
30%
31%       [keys,sections,subsections] = INIFILE(fName,'readall')
32%           Reads entire file and returns all the sections, subsections
33%           and keys found.
34%
35%
36%   Notes on the keys cell array given as an input parameter:
37%           Cell array of STRINGS; either 3, 4, or 5 columns.
38%           Each row has the same number of columns. The columns are:
39%           'section':      section name string (the root is considered if
40%                           empty)
41%           'subsection':   subsection name string (the root is considered
42%                           if empty)
43%           'key':          name of the field to write/read from (given as
44%                           a string).
45%           value:          (optional) STRING or NUMERIC value (scalar or
46%                           matrix) to be written to the
47%                           ini file in the case of 'write' operation OR
48%                           conversion CHAR for read operation:
49%                           'i' for integer, 'd' for double, 's' or
50%                           '' or not given for string (default).
51%           defaultValue:   (optional) string or numeric value (scalar or
52%                           matrix) that is returned when the key is not
53%                           found or an empty value is found
54%                           when reading ('read' operation).
55%                           If the defaultValue is not given and the key
56%                           is not found, an empty value is returned.
57%                           It MUST be in the format as given by the
58%                           value, e.g. if the value = 'i' it must be
59%                           given as an integer etc.
60%
61%
62%   EXAMPLE:
63%       Suppose we want a new ini file, test1.ini with 4 fields, including a
64%       5x5 matrix (see below). We can write the 5 fields into the ini file
65%       using:
66%
67%       x = rand(5);    % matrix data
68%       inifile('test1.ini','new');
69%       writeKeys = {'measurement','person','name','Primoz Cermelj';...
70%                   'measurement','protocol','id',1;...
71%                   'application','','description.m1','some...';...
72%                   'application','','description.m2','some...';...
73%                   'data','','x',x};
74%       inifile('test1.ini','write',writeKeys,'plain');
75%
76%       Later, you can read them out. Additionally, if any of them won't
77%       exist, a default value will be returned (if the 5-th column is given
78%       for all the rows as below).
79%   
80%       readKeys = {'measurement','person','name','','John Doe';...
81%                   'measurement','protocol','id','i',0;...
82%                   'application','','description.m1','','none';...
83%                   'application','','description.m2','','none';...
84%                   'data','','x','d',zeros(5)};
85%       readSett = inifile('test1.ini','read',readKeys);
86%
87%       Or, we can just read all the keys out
88%       [keys,sections,subsections] = inifile(test1.ini,'readall');
89%
90%
91%   NOTES: If the operation is 'write' and the file is empty or does not
92%   exist, a new file is created. When writing and if any of the section
93%   or subsection or key does not exist, it creates (adds) a new one.
94%   Everything but value is NOT case sensitive. Given keys and values
95%   will be trimmed (leading and trailing spaces will be removed).
96%   Any duplicates (section, subsection, and keys) are ignored. Empty
97%   section and/or subsection can be given as an empty string, '',
98%   but NOT as an empty matrix, [].
99%
100%   Numeric matrices can be represented as strings in one of the two form:
101%   '1 2 3;4 5 6' or '1,2,3;4,5,6' (an example).
102%
103%   Comment lines starts with ; as the first non-empty character but
104%   comments can not exist as a tail to a standard, non-comment line as ;
105%   is also used as a row delimiter for matrices.
106%
107%   This function was tested on the win32 platform only but it should
108%   also work on Unix/Linux platforms. Since some short-circuit operators
109%   are used, at least Matlab 6.5 (R13) is required.
110%
111%
112%   First release on 29.01.2003
113%   (c) Primoz Cermelj, Slovenia
114%   Contact: primoz.cermelj@gmail.com
115%   Download location: http://www.mathworks.com/matlabcentral/fileexchange/loadFile.do?objectId=2976&objectType=file
116%
117%   Version: 1.4.2
118%   Last revision: 12.01.2007
119%
120%   Bug reports, questions, etc. can be sent to the e-mail given above.
121%
122%   ACKNOWLEDGEMENTS: Thanks to Diego De Rosa for a suggestion/fix how to
123%   read the value when the key is found but empty.
124%--------------------------------------------------------------------------
125
126%----------------
127% INIFILE history
128%----------------
129%
130% [v.1.4.2] 12.01.2007
131% - FIX: When in read mode and a certain key is found but the value is
132%        empty, the default value will be used instead.
133%
134% [v.1.4.1] 12.01.2006
135% - FIX: Some minor refinements (speed,...)
136%
137% [v.1.4.0] 05.12.2006
138% - NEW: New 'readall' option added which reads all the sections,
139%        subsections and keys out
140%
141% [v.1.3.2 - v.1.3.5] 25.08.2004
142% - NEW: Speed improvement for large files - using fread and fwrite instead
143%        of fscanf and fprintf, respectively
144% - NEW: Some minor changes
145% - NEW: Writing speed-up
146% - NEW: New-line chars are properly set for pc, unix, and mac
147%
148% [v.1.3.1] 04.05.2004
149% - NEW: Comment lines are detected and thus ignored; comment lines are
150%        lines with first non-empty character being ;
151% - NEW: Lines not belonging to any of the recognized types (key, section,
152%        comment,...) raise an error.
153%
154% [v.1.3.0] 21.04.2004
155% - NEW: 2D Numeric matrices can be read/written
156% - FIX: Bug related to read operation and default value has been removed
157%
158% [v.1.2.0] 30.04.2004
159% - NEW: Automatic conversion capability (integers, doubles, and strings)
160%        added for read and write operations
161%
162% [v.1.1.0] 04.02.2004
163% - FIX: 'writetext' option removed (there was a bug previously)
164%
165% [v.1.01b] 19.12.2003
166% - NEW: A new concept - multiple keys can now be read, written, or deleted
167%        ALL AT ONCE which makes this function much faster. For example, to
168%        write 1000 keys, using previous versions it took 157 seconds on a
169%        1.5 GHz machine, with this new version it took only 0.9 seconds.
170%        In general, the speed improvement is greater when a larger number of
171%        read/written keys is considered (with respect to the older version).
172% - NEW: The format of the input parameters has changed. See above.
173%
174% [v.0.97] 19.11.2003
175% - NEW: Additional m-function, strtrim, is no longer needed
176%
177% [v.0.96] 16.10.2003
178% - FIX: Detects empty keys
179%
180% [v.0.95] 04.07.2003
181% - NEW: 'deletekey' option/operation added
182% - FIX: A major file refinement to obtain a more compact utility ->
183%        additional operations can "easily" be implemented
184%
185% [v.0.91-0.94]
186% - FIX: Some minor refinements
187%
188% [v.0.90] 29.01.2003
189% - NEW: First release of this tool
190%
191%----------------
192
193global NL_CHAR;
194
195% Checks the input arguments
196if nargin == 0
197    disp('INIFILE v1.4.2');
198    disp('Copyright (c) 2003-2007 Primoz Cermelj');
199    disp('This is FREE SOFTWARE');
200    disp('Type <help inifile> to get more help on its usage');
201    return
202elseif nargin < 2
203    error('Not enough input arguments');
204end
205
206fileName = varargin{1};
207operation = varargin{2};
208
209if (strcmpi(operation,'read')) | (strcmpi(operation,'deletekeys'))
210    if nargin < 3
211        error('Not enough input arguments.');
212    end
213    if ~exist(fileName)
214        error(['File ' fileName ' does not exist.']);
215    end
216    keys = varargin{3};
217    [m,n] = size(keys);
218    if n < 3
219        error('Keys argument must have at least 3 columns for read operation');
220    end
221    for ii=1:m
222        if isempty(keys(ii,3)) | ~ischar(keys{ii,3})
223            error('Empty or non-char keys are not allowed.');
224        end
225    end
226elseif (strcmpi(operation,'write'))
227    if nargin < 3
228        error('Not enough input arguments');
229    end
230    keys = varargin{3};
231    if nargin < 4 || isempty(varargin{4})
232        style = 'plain';
233    else
234        style = varargin{4};
235        if ~(strcmpi(style,'plain') | strcmpi(style,'tabbed')) | ~ischar(style)
236            error('Unsupported style given or style not given as a string');
237        end
238    end
239    [m,n] = size(keys);
240    if n < 4
241        error('Keys argument requires 4 columns for write operation');
242    end       
243    for ii=1:m
244        if isempty(keys(ii,3)) | ~ischar(keys{ii,3})
245            error('Empty or non-char keys are not allowed.');
246        end
247    end
248elseif (strcmpi(operation,'readall'))   
249    %
250elseif (~strcmpi(operation,'new'))
251    error(['Unknown inifile operation: ''' operation '''']);
252end
253if nargin >= 3
254    for ii=1:m
255        for jj=1:3
256            if ~ischar(keys{ii,jj})
257                error('All cells from the first 3 columns must be given as strings, even the empty ones.');
258            end
259        end
260    end
261end
262
263
264% Sets the new-line character/string
265if ispc
266    NL_CHAR = '\r\n';
267elseif isunix
268    NL_CHAR = '\n';
269else
270    NL_CHAR = '\r';
271end
272
273readsett = [];
274result = [];
275
276%----------------------------
277% CREATES a new, empty file (rewrites an existing one)
278%----------------------------
279if strcmpi(operation,'new')
280    fh = fopen(fileName,'w');
281    if fh == -1
282        error(['File: ''' fileName ''' can not be (re)created']);
283    end
284    fclose(fh);
285    return
286
287%----------------------------
288% READS the whole data (all keys)
289%----------------------------   
290elseif (strcmpi(operation,'readall'))
291    [keys,sections,subsections] = readallkeys(fileName);
292    varargout(1) = {keys};
293    varargout(2) = {sections};
294    varargout(3) = {subsections};
295    return   
296
297%----------------------------
298% READS key-value pairs out
299%----------------------------   
300elseif (strcmpi(operation,'read'))
301    result = cell(m,1);
302    if n >= 4
303        conversionOp = keys(:,4);       % conversion operation: 'i', 'd', or 's' ('') - for each key to be read
304    else
305        conversionOp = cellstrings(m,1);
306    end
307    if n < 5
308        defaultValues = cellstrings(m,1);
309    else
310        defaultValues = keys(:,5);
311    end
312    readsett = defaultValues;
313    keysIn = keys(:,1:3);
314    [secsExist,subsecsExist,keysExist,readValues,so,eo] = findkeys(fileName,keysIn);   
315    ind = find(keysExist);
316    % For those keys that exist but have empty values, replace them with
317    % the default values
318    if ~isempty(ind)
319        ind_empty = zeros(size(ind));
320        for kk = 1:size(ind,1)
321            ind_empty(kk) = isempty(readValues{ind(kk)});
322        end
323        ind(find(ind_empty)) = [];
324        readsett(ind) = readValues(ind);
325    end 
326    % Now, go through all the keys and do the conversion if the conversion
327    % char is given
328    for ii=1:m
329        if ~isempty(conversionOp{ii}) & ~strcmpi(conversionOp{ii},'s')
330            if strcmpi(conversionOp{ii},'i') | strcmpi(conversionOp{ii},'d')
331                if ~isnumeric(readsett{ii})
332                    readsett{ii} = str2num(readsett{ii});
333                end
334                if strcmpi(conversionOp{ii},'i')
335                    readsett{ii} = round(readsett{ii});
336                end
337                if isempty(readsett{ii})
338                    result{ii} = [num2str(ii) '-th key ' keysIn{ii,3} 'or given defaultValue could not be converted using ''' conversionOp{ii} ''' conversion'];
339                end
340            else
341                error(['Invalid conversion char given: ' conversionOp{ii}]);
342            end
343        end
344    end
345    varargout(1) = {readsett};
346    varargout(2) = {result};
347    return
348   
349%----------------------------
350% WRITES key-value pairs to an existing or non-existing
351% file (file can even be empty)
352%---------------------------- 
353elseif (strcmpi(operation,'write'))
354    if m < 1
355        error('At least one key is needed when writing keys');
356    end
357    if ~exist(fileName)
358        inifile(fileName,'new');
359    end
360    for ii=1:% go through ALL the keys and convert them to strings
361        keys{ii,4} = n2s(keys{ii,4});
362    end
363    writekeys(fileName,keys,style);
364    return
365   
366%----------------------------
367% DELETES key-value pairs out
368%----------------------------       
369elseif (strcmpi(operation,'deletekeys'))
370    deletekeys(fileName,keys);
371   
372   
373   
374else
375    error('Unknown operation for INIFILE.');
376end     
377
378
379
380
381%--------------------------------------------------
382%%%%%%%%%%%%% SUBFUNCTIONS SECTION %%%%%%%%%%%%%%%%
383%--------------------------------------------------
384
385
386%------------------------------------
387function [secsExist,subSecsExist,keysExist,values,startOffsets,endOffsets] = findkeys(fileName,keysIn)
388% This function parses ini file for keys as given by keysIn. keysIn is a cell
389% array of strings having 3 columns; section, subsection and key in each row.
390% section and/or subsection can be empty (root section or root subsection)
391% but the key can not be empty. The startOffsets and endOffsets are start and
392% end bytes that each key occuppies, respectively. If any of the keys doesn't exist,
393% startOffset and endOffset for this key are the same. A special case is
394% when the key that doesn't exist also corresponds to a non-existing
395% section and non-existing subsection. In such a case, the startOffset and
396% endOffset have values of -1.
397
398nKeys = size(keysIn,1);         % number of keys
399nKeysLocated = 0;               % number of keys located
400secsExist = zeros(nKeys,1);     % if section exists (and is non-empty)
401subSecsExist = zeros(nKeys,1);  % if subsection...
402keysExist = zeros(nKeys,1);     % if key that we are looking for exists
403keysLocated = keysExist;        % if the key's position (existing or non-existing) is LOCATED
404values = cellstrings(nKeys,1);  % read values of keys (strings)
405startOffsets = -ones(nKeys,1);  % start byte-position of the keys
406endOffsets = -ones(nKeys,1);    % end byte-position of the keys
407
408keyInd = find(strcmpi(keysIn(:,1),''));  % key indices having [] section (root section)
409
410line = [];
411lineN = 0;                      % line number
412currSection = '';
413currSubSection = '';
414
415fh = fopen(fileName,'r');
416if fh == -1
417    error(['File: ''' fileName ''' does not exist or can not be opened.']);
418end
419
420try
421    %--- Searching for the keys - their values and start and end locations in bytes
422    while 1
423       
424        pos1 = ftell(fh);
425        line = fgetl(fh);
426        if line == -1               % end of file, exit
427            line = [];
428            break
429        end
430        lineN = lineN + 1;
431        [status,readValue,readKey] = processiniline(line);       
432        if (status == 1)            % (new) section found
433            % Keys that were found as belonging to any previous section
434            % are now assumed as located (because another
435            % section is found here which could even be a repeated one)
436            keyInd = find( ~keysLocated & strcmpi(keysIn(:,1),currSection) ); 
437            if length(keyInd)
438                keysLocated(keyInd) = 1;
439                nKeysLocated = nKeysLocated + length(keyInd);
440            end
441            currSection = readValue;
442            currSubSection = '';
443            % Indices to non-located keys belonging to current section
444            keyInd = find( ~keysLocated & strcmpi(keysIn(:,1),currSection) ); 
445            if ~isempty(keyInd)
446                secsExist(keyInd) = 1;
447            end
448            pos2 = ftell(fh);
449            startOffsets(keyInd) = pos2+1;
450            endOffsets(keyInd) = pos2+1;
451        elseif (status == 2)        % (new) subsection found
452            % Keys that were found as belonging to any PREVIOUS section
453            % and/or subsection are now assumed as located (because another
454            % subsection is found here which could even be a repeated one)
455            keyInd = find( ~keysLocated & strcmpi(keysIn(:,1),currSection) & ~keysLocated & strcmpi(keysIn(:,2),currSubSection));
456            if length(keyInd)
457                keysLocated(keyInd) = 1;
458                nKeysLocated = nKeysLocated + length(keyInd);
459            end
460            currSubSection = readValue;
461            % Indices to non-located keys belonging to current section and subsection at the same time
462            keyInd = find( ~keysLocated & strcmpi(keysIn(:,1),currSection) & ~keysLocated & strcmpi(keysIn(:,2),currSubSection));
463            if ~isempty(keyInd)
464                subSecsExist(keyInd) = 1;
465            end
466            pos2 = ftell(fh);
467            startOffsets(keyInd) = pos2+1;
468            endOffsets(keyInd) = pos2+1;
469        elseif (status == 3)        % key found
470            if isempty(keyInd)
471                continue            % no keys from 'keys' - from section-subsection par currently in
472            end
473            currKey = readValue;
474            pos2 = ftell(fh);       % the last-byte position of the read key  - the total sum of chars read so far
475            for ii=1:length(keyInd)
476               if strcmpi( keysIn(keyInd(ii),3),readKey ) & ~keysLocated(keyInd(ii))
477                   keysExist(keyInd(ii)) = 1;
478                   startOffsets(keyInd(ii)) = pos1+1;
479                   endOffsets(keyInd(ii)) = pos2;
480                   values{keyInd(ii)} = currKey;
481                   keysLocated(keyInd(ii)) = 1;
482                   nKeysLocated = nKeysLocated + 1;
483               else
484                   if ~keysLocated(keyInd(ii))
485                       startOffsets(keyInd(ii)) = pos2+1;
486                       endOffsets(keyInd(ii)) = pos2+1;
487                   end
488               end
489            end
490            if nKeysLocated >= nKeys  % if all the keys are located stop the searching
491                break
492            end
493        else                          % general text found (even empty line(s))
494            if (status == -1)
495                error(['unknown string found at line ' num2str(lineN)]);
496            end
497        end       
498    %--- End of searching
499    end   
500    fclose(fh);
501catch
502    fclose(fh);
503    error(['Error parsing the file for keys: ' fileName ': ' lasterr]);
504end
505%------------------------------------
506
507
508
509
510%------------------------------------
511function writekeys(fileName,keys,style)
512% Writes keys to the section and subsection pair
513% If any of the keys doesn't exist, a new key is added to
514% the end of the section-subsection pair otherwise the key is updated (changed).
515% Keys is a 4-column cell array of strings.
516
517global NL_CHAR;
518
519RETURN = sprintf('\r');
520NEWLINE = sprintf('\n');
521
522[m,n] = size(keys);
523if n < 4
524    error('Keys to be written are given in an invalid format.');
525end
526
527% Get keys position first using findkeys
528keysIn = keys;   
529[secsExist,subSecsExist,keysExist,readValues,so,eo] = findkeys(fileName,keys(:,1:3));
530
531% Read the whole file's contents out
532fh = fopen(fileName,'r');
533if fh == -1
534    error(['File: ''' fileName ''' does not exist or can not be opened.']);
535end
536try
537    dataout = fread(fh,'char=>char')';
538catch
539    fclose(fh);
540    error(lasterr);
541end
542fclose(fh);
543
544%--- Rewriting the file -> writing the refined contents
545fh = fopen(fileName,'w');
546if fh == -1
547    error(['File: ''' fileName ''' does not exist or can not be opened.']);
548end
549try
550    tab1 = [];
551    if strcmpi(style,'tabbed')
552        tab1 = sprintf('\t');
553    end
554    % Proper sorting of keys is cruical at this point in order to avoid
555    % inproper key-writing.
556   
557    % Find keys with -1 offsets - keys with non-existing section AND
558    % subsection - keys that will be added to the end of the file   
559    fs = length(dataout);       % file size in bytes
560    nAddedKeys = 0;
561    ind = find(so==-1);
562    if ~isempty(ind)       
563        so(ind) = (fs+10);      % make sure these keys will come to the end when sorting
564        eo(ind) = (fs+10);
565        nAddedKeys = length(ind);
566    end
567   
568    % Sort keys according to start- and end-offsets
569    [dummy,ind] = sort(so,1);
570    so = so(ind);
571    eo = eo(ind);
572    keysIn = keysIn(ind,:);
573    keysExist = keysExist(ind);
574    secsExist = secsExist(ind);
575    subSecsExist = subSecsExist(ind);
576    readValues = readValues(ind);
577    values = keysIn(:,4);   
578
579    % Find keys with equal start offset (so) and additionally sort them
580    % (locally). These are non-existing keys, including the ones whose
581    % section and subsection will also be added.
582    nKeys = size(so,1);
583    fullInd = 1:nKeys;
584    ii = 1;
585    while ii < nKeys
586        ind = find(so==so(ii));
587        if ~isempty(ind) && length(ind) > 1
588            n = length(ind);
589            from = ind(1);
590            to = ind(end);
591            tmpKeys = keysIn( ind,: );
592            [tmpKeys,ind2] = sortrows( lower(tmpKeys) );
593            fullInd(from:to) = ind(ind2);
594            ii = ii + n;
595        else
596            ii = ii + 1;
597        end
598    end
599   
600    % Final (re)sorting
601    so = so(fullInd);
602    eo = eo(fullInd);
603    keysIn = keysIn(fullInd,:);
604    keysExist = keysExist(fullInd);
605    secsExist = secsExist(fullInd);
606    subSecsExist = subSecsExist(fullInd);
607    readValues = readValues(fullInd);
608    values = keysIn(:,4);   
609   
610    % Refined data - datain
611    datain = [];
612   
613    for ii=1:nKeys      % go through all the keys, existing and non-existing ones
614        if ii==1
615            from = 1;   % from byte-offset of original data (dataout)
616        else
617            from = eo(ii-1);
618            if keysExist(ii-1)
619                from = from + 1;
620            end
621        end
622        to = min(so(ii)-1,fs);  % to byte-offset of original data (dataout)
623       
624        if ~isempty(dataout)
625            datain = [datain dataout(from:to)];    % the lines before the key
626        end
627       
628        if length(datain) & (~(datain(end)==RETURN | datain(end)==NEWLINE))
629            datain = [datain, sprintf(NL_CHAR)];
630        end
631
632        tab = [];
633        if ~keysExist(ii) 
634            if ~secsExist(ii) && ~isempty(keysIn(ii,1))
635                if ~isempty(keysIn{ii,1})
636                    datain = [datain sprintf(['%s' NL_CHAR],['[' keysIn{ii,1} ']'])];
637                end               
638                % Key-indices with the same section as this, ii-th key (even empty sections are considered)
639                ind = find( strcmpi( keysIn(:,1), keysIn(ii,1)) );
640                % This section exists at all keys  corresponding to the same section from know on (even the empty ones)
641                secsExist(ind) = 1;
642            end
643            if ~subSecsExist(ii) && ~isempty(keysIn(ii,2))
644                if ~isempty( keysIn{ii,2})
645                    if secsExist(ii); tab = tab1;  end;
646                    datain = [datain sprintf(['%s' NL_CHAR],[tab '{' keysIn{ii,2} '}'])];
647                end
648                % Key-indices with the same section AND subsection as this, ii-th key
649                % (even empty sections and subsections are considered)
650                ind = find( strcmpi( keysIn(:,1), keysIn(ii,1)) & strcmpi( keysIn(:,2), keysIn(ii,2)) );
651                % This subsection exists at all keys corresponding to the
652                % same section and subsection from know on (even the empty ones)
653                subSecsExist(ind) = 1;
654            end
655        end
656        if secsExist(ii) & (~isempty(keysIn{ii,1})); tab = tab1;  end;
657        if subSecsExist(ii) & (~isempty(keysIn{ii,2})); tab = [tab tab1];  end;
658        datain = [datain sprintf(['%s' NL_CHAR],[tab keysIn{ii,3} ' = ' values{ii}])];
659    end
660    from = eo(ii);
661    if keysExist(ii)
662        from = from + 1;
663    end
664    to = length(dataout);
665    if from < to
666        datain = [datain dataout(from:to)];
667    end
668    fwrite(fh,datain,'char');
669catch
670    fclose(fh);
671    error(['Error writing keys to file: ''' fileName ''' : ' lasterr]);
672end
673fclose(fh);
674%------------------------------------
675
676
677
678%------------------------------------
679function deletekeys(fileName,keys)
680% Deletes keys and their values out; keys must have at least 3 columns:
681% section, subsection, and the key
682
683[m,n] = size(keys);
684if n < 3
685    error('Keys to be deleted are given in an invalid format.');
686end
687
688% Get keys position first
689keysIn = keys;   
690[secsExist,subSecsExist,keysExist,readValues,so,eo] = findkeys(fileName,keys(:,1:3));
691
692% Read the whole file's contents out
693fh = fopen(fileName,'r');
694if fh == -1
695    error(['File: ''' fileName ''' does not exist or can not be opened.']);
696end
697try
698    dataout = fread(fh,'char=>char')';
699catch
700    fclose(fh);
701    rethrow(lasterror);
702end
703fclose(fh);
704
705%--- Rewriting the file -> writing the refined content
706fh = fopen(fileName,'w');
707if fh == -1
708    error(['File: ''' fileName ''' does not exist or can not be opened.']);
709end
710try
711    ind = find(keysExist);
712    nExistingKeys = length(ind);
713    datain = dataout;
714   
715    if nExistingKeys
716        % Filtering - retain only the existing keys...
717        fs = length(dataout);       % file size in bytes
718        so = so(ind);
719        eo = eo(ind);
720        keysIn = keysIn(ind,:);
721        % ...and sorting
722        [so,ind] = sort(so);
723        eo = eo(ind);
724        keysIn = keysIn(ind,:);
725       
726        % Refined data - datain
727        datain = [];
728       
729        for ii=1:nExistingKeys  % go through all the existing keys
730            if ii==1
731                from = 1;   % from byte-offset of original data (dataout)
732            else
733                from = eo(ii-1)+1;
734            end
735            to = so(ii)-1;  % to byte-offset of original data (dataout)
736           
737            if ~isempty(dataout)
738                datain = [datain dataout(from:to)];    % the lines before the key
739            end       
740        end
741        from = eo(ii)+1;
742        to = length(dataout);
743        if from < to
744            datain = [datain dataout(from:to)];
745        end
746    end
747   
748    fwrite(fh,datain,'char');
749catch
750    fclose(fh);
751    error(['Error deleting keys from file: ''' fileName ''' : ' lasterr]);
752end
753fclose(fh);
754%------------------------------------
755
756
757
758
759%------------------------------------
760function [keys,sections,subsections] = readallkeys(fileName)
761% Reads all the keys out as well as the sections and subsections
762
763keys = [];
764sections = [];
765subsections = [];
766% Read the whole file's contents out
767try
768    dataout = textread(fileName,'%s','delimiter','\n');
769catch
770    error(['File: ''' fileName ''' does not exist or can not be opened.']);
771end
772nLines = size(dataout,1);
773
774% Go through all the lines and construct the keys variable
775keys = cell(nLines,4);
776sections = cell(nLines,1);
777subsections = cell(nLines,2);
778keyN = 0;
779secN = 0;
780subsecN = 0;
781secStr = '';
782subsecStr = '';
783for ii=1:nLines
784    [status,value,key] = processiniline(dataout{ii});
785    if status == 1
786        secN = secN + 1;
787        secStr = value;
788        sections(secN) = {secStr};
789    elseif status == 2
790        subsecN = subsecN + 1;
791        subsecStr = value;
792        subsections(subsecN,:) = {secStr,subsecStr};
793    elseif status == 3
794        keyN = keyN + 1;
795        keys(keyN,:) = {secStr,subsecStr,key,value};
796    end
797end
798keys(keyN+1:end,:) = [];
799sections(secN+1:end,:) = [];
800subsections(subsecN+1:end,:) = [];
801%------------------------------------
802
803
804
805%------------------------------------
806function [status,value,key] = processiniline(line)
807% Processes a line read from the ini file and
808% returns the following values:
809%   - status:  -1   => unknown string found
810%               0   => empty line found
811%               1   => section found
812%               2   => subsection found
813%               3   => key-value pair found
814%               4   => comment line found (starting with ;)
815%   - value:    value-string of a key, section, subsection, comment, or unknown string
816%   - key:      key as string
817
818status = 0;
819value = [];
820key = [];
821line = strim(line);                         % removes any leading and trailing spaces
822if isempty(line)                            % empty line
823    return
824end
825if strcmpi(line(1),';')                     % comment found
826    status = 4;
827    value = line(2:end);
828elseif (line(1) == '[') & (line(end) == ']') & (length(line) >= 3)  % section found
829    value = lower(line(2:end-1));
830    status = 1;
831elseif (line(1) == '{') &...                % subsection found
832       (line(end) == '}') & (length(line) >= 3)
833    value = lower(line(2:end-1));
834    status = 2;
835else                                        % either key-value pair or unknown string
836    pos = findstr(line,'=');
837    if ~isempty(pos)                        % key-value pair found
838        status = 3;
839        key = lower(line(1:pos-1));
840        value = line(pos+1:end);
841        key = strim(key);                   % removes any leading and trailing spaces
842        value = strim(value);               % removes any leading and trailing spaces
843        if isempty(key)                     % empty keys are not allowed
844            status = 0;
845            key = [];
846            value = [];
847        end
848    else                                    % unknown string found
849        status = -1;
850        value = line;
851    end
852end
853
854
855%------------------------------------
856function outstr = strim(str)
857% Removes leading and trailing spaces (spaces, tabs, endlines,...)
858% from the str string.
859if isnumeric(str);
860    outstr = str;
861    return
862end
863ind = find( ~isspace(str) );        % indices of the non-space characters in the str   
864if isempty(ind)
865    outstr = [];       
866else
867    outstr = str( ind(1):ind(end) );
868end
869
870
871
872%------------------------------------
873function cs = cellstrings(m,n)
874% Creates a m x n cell array of empty strings - ''
875cs = cell(m,n);
876cs(:) = {''};
877
878
879%------------------------------------
880function y = n2s(x)
881% Converts numeric matrix to string representation.
882% Example: x given as [1 2;3 4] returns y = '1,2;3;4'
883if ischar(x) | isempty(x)
884    y = x;
885    return
886end
887[m,n] = size(x);
888y = [num2str(x(1,:),'%15.6g')];
889for ii=2:m
890    y = [y ';' num2str(x(ii,:),'%15.6g')];
891end
Note: See TracBrowser for help on using the repository browser.