function [X,FULLFMT] = saveascii(X,varargin)
%SAVEASCII Save/display a matrix with specific format for each column.
%
% SYNTAX:
% saveascii(X) % Displays
% saveascii(X,...,FMT)
% saveascii(X,...,DLM)
% saveascii(X,FILE,...) % Saves
% saveascii(X,FILE,...,'a') % Appends
% [Y,FULLFMT] = saveascii(...);
%
% INPUT:
% X - 2-dimensional numeric, logical or string array with Ncol
% columns to be saved/display, with/without NaNs, or a vector of
% cell of strings.
% DLM - One or Ncol-1 strings on a cell specifying the delimiter(s)
% between every/each pair if columns.
% DEFAULT: {' '} or {''} (the latter if X is char)
% FMT - One or Ncol integers in a vector specifying the PRECISION for
% every/each column, or One or Ncol strings in a cell specifying
% its format(s). See NOTE below.
% DEFAULT: '% 8.7e' or '%c' (the latter if X is char)
% FILE - File name or identifier specifying the output file.
% DEFAULT: not used (just displays)
% 'a' - Appends to the given FILE in text mode. Use 'w -i' to active a
% OVERWRITE warning. See NOTE below.
% DEFAULT: 'w' (creates/OVERWRITES! the given FILE in text mode)
%
% OUTPUT (all optional):
% Y - Matrix X converted to a string with specified format(s) and
% delimiter(s).
% FULLFMT - Format used to save/dislay the matrix. If X is a cell of
% strings, this is also a cell of strings without the End of
% Line.
%
% DESCRIPTION:
% This program saves/displays a matrix array by using SPRINTF/FPRINTF
% with specific format (FMT) and delimiter (DLM) for every or EACH
% column in a very handy way, which is the mayor difference with SAVE
% or DLMWRITE function.
%
% The point of this program is to allow the user to save/display any
% numeric or char matrix as easy as posible without messing with the
% appropiate format ('%...') to do it, only with the precision (if is
% numerical). See the EXAMPLE below.
%
% NOTE:
% * Optional inputs use its DEFAULT value when not given or [].
% * Optional outputs may or not be called.
% * FMT and DLM may be a single string.
% * When FMT is used as precision integers, negative ones indicates to
% treat column(s) of X as integers rounded up to those significant
% digits to the left!
% * ADDITIONAL NOTES are included inside this file.
%
% EXAMPLE:
% x = [ 1 2 pi
% 4 NaN 6
% 75.4 Inf 8.5 ];
% % Display with 3 significant decimals.
% saveascii(x,3)
% % RETURNS:
% % 1.000 2.000 3.142
% % 4.000 NaN 6.000
% % 75.400 Inf 8.500
% %
% % Display with specific significant decimals.
% saveascii(x,[-1 2 0])
% % RETURNS:
% % 0 2.00 3
% % 0 NaN 6
% % 80 Inf 9
% %
% % Displays with ' hello ' and ' bye ' as delimiter.
% saveascii(x,{' hello ',' bye '},2)
% % RETURNS:
% % 1.00 hello 2.00 bye 3.14
% % 4.00 hello NaN bye 6.00
% % 75.40 hello Inf bye 8.50
% %
% % Saves on 'saveascii_demo.txt' with heading.
% FILE = 'saveascii_demo.txt';
% saveascii('% Demo file' ,FILE)
% saveascii(['% Pi = ' saveascii(pi,3) ';'],FILE,'a')
% saveascii(x ,FILE,'a',0)
% edit(FILE)
% demo = load(FILE)
% % RETURNS:
% % demo =
% %
% % 4 NaN 6
% % 75 Inf 9
% %
% % NOTE: see how the heading is ignored by the LOAD function.
%
% SEE ALSO:
% SAVE, FPRINTF, SPRINTF, DLMWRITE, CSVWRITE, FOPEN, STR2DOUBLE,
% STR2NUM, NUM2STR
% and
% READLINE by Carlos Vargas
% at http://www.mathworks.com/matlabcentral/fileexchange
%
%
% ---
% MFILE: saveascii.m
% VERSION: 6.2 (Oct 30, 2009) (download)
% MATLAB: 7.7.0.471 (R2008b)
% AUTHOR: Carlos Adrian Vargas Aguilera (MEXICO)
% CONTACT: nubeobscura@hotmail.com
% ADDITIONAL NOTES:
% * X must be the first input always, and, if used, FILE must be the
% second one. Afterwards FMT, DLM and 'a' may be given in any order.
% * By default the program writes with in text mode by append a 't' in
% the open permission mode ('wt' or 'at') rather than in the default
% binary mode ('wb' or 'ab'). This allows Windows OS users to read
% the saved file with any ascii program. See FOPEN for more details.
% * By default, the program OVERWRITES without warning, to use a
% warning use the optional input 'w -i' instead of the default 'w'.
% * To create a NEWLINE the program uses: '\n'. I guess Mac OS users
% should change the program to use '\r' instead.
% * The program works faster when a single delimiter and format/
% precision are used for every column.
% * The FMT may be a FULL format, which is a single string with Ncol
% formats within as the FULLFMT output.
% REVISIONS:
% 1.0 Released. (Mar 06, 2006)
% 2.0 Allows delimiter and format for each column. (Sep 28, 2006)
% 2.1 English translation from spanish. (Nov 13, 2006)
% 3.0 Now allows input decimals for floating-point. 'wt' and 'at'
% for Windows users. Output to Command Window and check errors.
% (Feb 21, 2007)
% 3.1 Now accepts zero and negative decimals. (Feb 26, 2007)
% 3.1.1 Bug fixed with row vectors (thanks to Emilio Velazquez). (Mar
% 01, 2007)
% 3.1.2 Bug fixed on get_digits subfunction. Used SUM of logicals
% instead of ANY. (Mar 02, 2007)
% 4.0 Cleaner and rewritten code (cells). Reduced running time and
% memmory usage. Fixed bugs. Accounts Inf and NaN's. Changed
% default delimiter '\t' to ' '. Changed beginner char '@' to
% '<'. Added ending option. Optionaly format string output. (Mar
% 11, 2008)
% 4.0.1 Fix little bug with INTEGER type. (Mar 13, 2008)
% 4.0.2 Fixed bug with not numeric elements (NAN's, Inf's and -Inf's).
% (Mar 13, 2008)
% 4.0.3 Fixed bug when the whole column is no finite (NaN, Inf, or
% -Inf's). (May 06, 2008)
% 5.0 Rewritten help and code. Fixed minor bugs related with empty
% X. No more reversed outputs. No more Begginig and Ending
% string optional inputs allowed. No more inputs separated by
% commas for DLM, FMT or precision FMT are allowed, instead cell
% of strings or a vector of integers must be used. DLM optional
% input is forced to be a cell of strings. New overwrite warning
% added. (Jun 08, 2009)
% 5.0.1 When FMT is numeric (precision) now the program rounds up to
% it before saving. This eliminates any negative zero output
% like '-0.00'. (Jun 19, 2009)
% 6.0 Now save a cell of strings. Again accepts a single delimiter
% as string. (Sep 30, 2009)
% 6.1 Ignores optional empty inputs. Added some title comments (Oct
% 03, 2009)
% 6.2 Fixed small bug with parse inputs. Now creates file directory
% if not exist. (Oct 30, 2009)
% DISCLAIMER:
% saveascii.m is provided "as is" without warranty of any kind, under the
% revised BSD license.
% Copyright (c) 2004,2006,2007,2008,2009 Carlos Adrian Vargas Aguilera
% INPUTS CHECK-IN
% -------------------------------------------------------------------------
% Checks number of inputs and outputs.
if nargin<1
error('CVARGAS:saveascii:notEnoughInputs',...
'At least 1 input is required.')
elseif nargin>5
error('CVARGAS:saveascii:tooManyInputs',...
'At most 5 inputs are allowed.')
elseif nargout>2
error('CVARGAS:saveascii:tooManyOutputs',...
'At most 2 outputs are allowed.')
end
% Sets defaults:
FILE = []; % Function mode:
% [] : display
% filename/fid : save
PER = 'w'; % Open permission:
% 'w' : OVERWRITES without warning
% 'a' : ppends
TOB = 't'; % Write mode:
% 't' : text
% 'b' : binary (FOPEN default)
WAR = false; % Overwrite warning:
% false : do not warns
% true : do warns
if ischar(X) ||... % String matrix
iscellstr(X) % or cell of strings input:
FMT = {'%c'}; % Format string for each (every) column.
DLM = {''}; % If just text, nothing between chars.
else % Numeric (real) or logical matrix input:
FMT = {'% 8.7e'}; % Ugly, but MATLAB seems to like it, do you?
DLM = {' '}; % Single space. Try '\t' (tab).
end %
BOEL = ''; % String at the Begining of Each line.
EOEL = '\n'; % String at the End Of Each Line
% '\n' : for Windows and Unix OS users
% '\r' : for Mac OS users (I guess, not tested)
PRE = []; % Not used by default.
WID = []; % Not used by default.
SPC = 'f'; % Floating-point specifier.
% CHECKS X ================================================================
% Checks X size.
Nrow = size(X);
if length(Nrow)>2
error('CVARGAS:saveascii:incorrectXDimension',...
'X must be a 2-dimensional matrix array.')
else
Ncol = Nrow(2);
Nrow = Nrow(1);
end
% Checks X empty, type and complex.
Xemp = isempty(X);
Xnum = false;
Xcell = false;
if ~Xemp && (isnumeric(X) || islogical(X)) % Fixed BUG (May 07, 2009)
if ~isreal(X)
warning('CVARGAS:saveacii:complexInput',...
'Imaginary parts on X were ignored.')
X = real(X);
end
Xnum = true;
elseif ischar(X)
% continue
elseif iscellstr(X)
Xcell = true;
if Ncol>1
if Nrow~=1
error('CVARGAS:saveascii:incorrectXCellSize',...
'X must be a vector of cell of strings, not a matrix.')
end
Nrow = Ncol;
Ncol = 1;
end
X = X(:);
Ncolcell = cellfun(@length,X);
if Nrow==1
% Cell of length 1?
X = X{1};
Xcell = false;
end
elseif ~Xemp
error('CVARGAS:saveascii:incorrectXType',...
'X must be numerical, logical, string or cell of strings type.')
end
% CHECKS VARARGIN =========================================================
% Checks number of optional inputs by type.
% Fixed bug with empty inputs. Oct 2009
Nopt = length(varargin);
inum = false(1,Nopt);
ichar = inum;
icell = inum;
iempty = inum;
for k = 1:Nopt
if isempty(varargin{k})
iempty(k) = true;
elseif ischar(varargin{k})
ichar(k) = true;
elseif iscellstr(varargin{k})
icell(k) = true; % Fixed bug, Oct 2009
elseif isnumeric(varargin{k})
inum(k) = true; % Fixed bug, Oct 2009
else
error('CVARGAS:saveascii:incorrectTypeInput',...
'Optional inputs must be numerical, char or cell of strings type.')
end
end
% Checks numeric inputs.
[newFILE,PRE] = get_num(PRE,Ncol,varargin(inum),find(inum),find(iempty));
clear inum iempty
% Gets format.
newFMT = [];
if Xnum
% Checks PRE.
% Avoids a subfunction to optimize memory usage.
if ~isempty(PRE)
% Rounds down to positive PRE and up to negative PRE.
ind = (PRE<0);
if any(ind)
% Negative PRE.
if length(PRE)==1
temp = 10^PRE;
X = round(X*temp)/temp;
else
temp = repmat(10.^PRE(ind),Nrow,1);
X(:,ind) = round(X(:,ind).*temp)./temp;
end
clear temp
PRE(ind) = 0;
end
if any(~ind) % (Fixed BUG, Jun 19 2009)
% Positive PRE.
if length(PRE)==1
temp = 10^PRE;
X = round(X*temp)/temp;
else
temp = repmat(10.^PRE(~ind),Nrow,1);
X(:,~ind) = round(X(:,~ind).*temp)./temp;
end
clear temp
end
X(X==0) = 0; % Forces positive zeros.
% Generate format from precision.
% First, creates a short matrix x3 to get the width and helps to save
% memory, with only 3 rows:
% 1. Maximum of X columns (ignoring Inf's)
% 2. Flags if columns of X has: NaN->1; Inf->1; -Inf->-1; otherwise->0
% 3. Minimum of X columns (ignoring -Inf's)
iinf = ~isfinite(X); % 1's if NaN, Inf or -Inf, 0 otherwise.
iinfn = find(iinf); % To get the -Inf indexes:
iinfn(isnan(X(iinfn)) ) = []; % ... deletes the NaN's. Bug fixed mar08
iinfn( X(iinfn)>0) = []; % ... deletes the Inf's
iinf = double(iinf); % Turns them to double values
iinf(iinfn) = -1; % Put -Inf flags as -1.
x3 = [maxinf(X,[],1); any(iinf,1)-2*any(iinf<0,1); mininf(X,[],1)];
clear iinf iinfn
% Creates the format string from precision options.
newFMT = pre2fmt(PRE,WID,SPC,Ncol,x3);
clear x3
end
else
if ~isempty(PRE)
error('CVARGAS:saveascii:incorrectFmtNumericalInput',...
'FMT cannot be numerical because X is not numeric.')
end
end
% Checks cell inputs:
[newDLM,newFMT,EOEL,full1] = ...
get_cell([],newFMT,EOEL,Ncol,varargin(icell));
clear icell
% Checks string inputs.
% Fixed bug to work with char DELIMITERS besides of cells. Sep 2009.
[newFILE,PER,TOB,WAR,newDLM,newFMT,EOEL,full2] = get_char(newFILE,PER,...
TOB,WAR,newDLM,newFMT,EOEL,Ncol,varargin(ichar),find(ichar));
clear ichar varargin
% CHECKS FORMAT ===========================================================
% Given FMT?:
if ~isempty(newFMT)
if ~Xnum
warning('CVARGAS:saveascii:incorrectFmtCharInput',...
'Ignored specific format because X is char.')
else
FMT = newFMT;
end
end
% Given DLM:
if ~isempty(newDLM)
if full1 || full2
warning('CVARGAS:saveascii:ignoredDlmInput',...
'DLM ignored because FMT is a full format.')
DLM = {''};
else
DLM = newDLM;
end
end
% Generates full format:
if ~Xemp
if ~Xcell
FULLFMT = [BOEL get_strform(DLM,FMT,Ncol) EOEL];
else
FULLFMT = cell(Nrow,1);
eoel = EOEL;
if ~isempty(EOEL)
for k = 1:2
if strcmp(eoel(end-1:end),'\n')
eoel(end-1:end) = [];
elseif strcmp(eoel(end-1:end),'\r')
eoel(end-1:end) = [];
end
if isempty(eoel), break, end
end
elseif length(FMT)>1
for k = 1:2
if isempty(FMT), break, end
if strcmp(FMT(end-1:end),'\n')
EOEL = FMT(end-1:end);
FMT(end-1:end) = [];
elseif strcmp(FMT(end-1:end),'\r')
EOEL = FMT(end-1:end);
FMT(end-1:end) = [];
end
end
end
for k = 1:Nrow
FULLFMT{k} = [BOEL get_strform(DLM,FMT,Ncolcell(k)) eoel];
end
end
else
% Empty array.
X = ''; % Fixed BUG (May 07, 2009)
FULLFMT = '';
end
clear BOEL WID FMT DLM SPC Ncol
% CHECKS FILE =============================================================
% Given FILE?:
if ~isempty(newFILE)
FILE = newFILE;
% Warning for the file id used. To check that FILE is a fid and not a
% precision.
if isempty(PRE) && isempty(newFMT) && isnumeric(FILE)
if ~isempty(fopen(FILE))
warning('CVARGAS:saveascii:usedFileNumericalInput',...
'Filename used was ''%s'' with file identifier %.0f.',fopen(FILE),FILE)
% To ignore this warning use
% >> warning('off','CVARGAS:saveascii:usedFileNumericalInput')
% before calling this program.
else
error('CVARGAS:saveascii:invalidNumericalSecondInput',...
['Numerical second input must be a valid File Identifier. If it is '...
'PRECISION, give an empty, [], as second input.'])
end
end
end
if ~isempty(FILE) && isnumeric(FILE)
% File id:
fid = FILE;
[FILE,per] = fopen(fid);
if ~ismember(per(1),'aAwW')
error('CVARGAS:saveascii:noWrittingPermission',...
['Filename ''%s'' with file identifier %.0f does not have writting ' ...
'permision. See FOPEN for details.'],fopen(FILE),FILE)
end
if Xcell && ~ismember(per(1),'aA')
error('CVARGAS:saveascii:noAppendPermission',...
['Filename ''%s'' with file identifier %.0f does not have append ' ...
'permision. Elements of cell X will overwrite the file each time.']...
,fopen(FILE),FILE)
end
else
fid = [];
end
Femp = isempty(FILE);
if (~Femp && WAR) && ((isempty(fileparts(FILE)) && ...
(exist(fullfile(pwd,FILE),'file')==2)) || (exist(FILE,'file')==2))
% Overwrite warning.
h = questdlg({'Is it OK to overwrite the file:'; [FILE '?']},...
'saveascii.m','Yes','Cancel','Cancel');
if isempty(h) || ~strcmp(h,'Yes')
if nargout==0
clear X
return
end
Femp = true;
end
end
clear newFILE
clear newFMT
% -------------------------------------------------------------------------
% MAIN
% -------------------------------------------------------------------------
% SAVES IN FILE ===========================================================
if ~Femp
% Saves the matrix to the ascii file using FPRINTF.
if ~isempty(fid)
if ~Xcell
fprintf(fid,FULLFMT,X.');
else
for k = 1:Nrow
fprintf(fid,FULLFMT{k},X{k}.');
end
end
else
% Fixed bug. Oct 2009
[DIR FILE EXT] = fileparts(FILE);
if ~isempty(DIR)
if ~(exist(DIR,'dir')==7)
[flag,temp] = mkdir(DIR);
if ~flag
error('CVARGAS:saveascii:invalidDirectoryName',...
'Unable to create the output directory ''%s''.',DIR)
end
end
end
FILE = fullfile(DIR,[FILE EXT]);
fid = fopen(FILE,[PER TOB]); % 1.
if fid<0
error('CVARGAS:incorrectFileStringInput',...
['FILE was not a valid file name. If it is a DELIMITER put it ' ...
'between brackets, {}, or put an empty, [], in the second input.'])
end
if ~Xcell
fprintf(fid,FULLFMT,X.'); % 2.
fclose(fid); % 3. lines of the SAVEASCII v1.0
else
% Writes first element and then appends the others.
fprintf(fid,[FULLFMT{1} EOEL],X{1}.');
fclose(fid);
fid = fopen(FILE,['a' TOB]);
for k = 2:Nrow
fprintf(fid,[FULLFMT{k} EOEL],X{k}.');
end
fclose(fid);
end
end
if (nargout==0)
clear X
return
end
end
% DISPLAYS IN COMMAND WINDOW ==============================================
if nargout==0
if ~Xcell
% Display string matrix.
if ~Xnum && (Xemp || isempty(newDLM)) % Fixed BUG (May 07, 2009)
disp(X)
clear X
return
end
X = sprintf(FULLFMT,X.');
if isempty(X)
% Incorrect FULLFMT.
error('CVARGAS:saveascii:incorrectFormat',...
'Incorrect format.')
end
Ncol2 = numel(X)/Nrow;
if isnatural(Ncol2) % Reshapes it into a string matrix.
Y = reshape(X,Ncol2,Nrow);
Yn = double(Y(end,1));
if all(Yn==double(sprintf(FULLFMT(end-1:end))))
Y = Y(1:end-1,:)';
X = Y;
else
warning('CVARGAS:saveascii:matrixNotSquare',...
['The displayed string matrix is a vector because the array ' ...
'cannot be squared with this format.'])
% NOTE: SAVEASCII tries to convert the output from SPRINTF, which is a
% vector string, to a matrix string but fails, probably due to an
% incorrect format row.
end
elseif ~isempty(X)
warning('CVARGAS:saveascii:matrixNotSquare',...
['The displayed string matrix is a vector because the array ' ...
'cannot be squared with this format.'])
% NOTE: SAVEASCII tries to convert the output from SPRINTF, which is a
% vector string, to a matrix string but fails, probably due to an
% incorrect format row.
end
disp(X)
else
for k = 1:Nrow
fprintf(1,[FULLFMT{k} EOEL],X{k}.')
end
end
clear X
return
end
% OUTPUTS VARIABLE ========================================================
% Output or displays the result.
% Displays the result matrix string on the Command Window or as an output
% argument using SPRINTF and DISP.
% Fixed BUG (May 07, 2009).
if ~Xnum && (Xemp || (isempty(newDLM) && ~Xcell))
return
end
% Output string matrix.
if ~Xcell
X = sprintf(FULLFMT,X.');
Ncol2 = numel(X)/Nrow;
if isnatural(Ncol2) % Reshapes it into a string matrix.
Y = reshape(X,Ncol2,Nrow);
Yn = double(Y(end,1));
if all(Yn==double(sprintf(FULLFMT(end-1:end))))
Y = Y(1:end-1,:)';
X = Y;
else
warning('CVARGAS:saveascii:matrixNotSquare',...
['The displayed string matrix is a vector because the array ' ...
'cannot be squared with this format.'])
% NOTE: SAVEASCII tries to convert the output from SPRINTF, which is a
% vector string, to a matrix string but fails, probably due to an
% incorrect format row.
end
elseif ~isempty(X)
warning('CVARGAS:saveascii:matrixNotSquare',...
['The output string matrix is a vector because the array ' ...
'cannot be squared with this format.'])
% NOTE: SAVEASCII tries to convert the output from SPRINTF, which is a
% vector string, to a matrix string but fails, probably due to an
% incorrect format row.
end
else
Y = cell(Nrow,1);
for k = 1:Nrow
Y{k} = sprintf(FULLFMT{k},X{1}.');
X(1) = [];
end
Mcolcell = cellfun(@length,Y);
X = repmat(' ',Nrow,max(Mcolcell));
for k = 1:Nrow
X(k,1:Mcolcell(k)) = Y{1};
Y(1) = [];
end
end
% =========================================================================
% SUBFUNCTIONS
% -------------------------------------------------------------------------
function [fid,PRE] = get_num(PRE,Ncol,numopt,inum,iempty)
% Extract precision from options in a vector array.
% New input "iempty". Oct 2009.
% Forces row PRE:
PRE = round(PRE(:).');
fid = [];
% Checks no input.
if isempty(numopt)
return
end
% Checks FILE id input.
% Fixed bug to accept 1 and 2 file identifiers. Oct 2009.
if isempty(iempty) && inum(1)==1 && (numel(numopt{1})==1) && ...
(numopt{1}>0) && isnatural(numopt{1}) && ~isempty(fopen(numopt{1}))
fid = numopt{1};
numopt(1) = [];
if isempty(numopt)
return
end
end
% Checks X empty:
if Ncol==0
return
end
% Checks many inputs.
if length(numopt)>1
error('CVARGAS:saveascii:tooManyFmtInput',...
'More than one FMT precision given.')
end
% Checks values:
if any(~isfinite(numopt{1}))
error('CVARGAS:saveascii:notFiniteFmtInput',...
'Precision FMT must be all finite.')
end
% Checks size:
nPRE = numel(numopt{1});
if (nPRE~=1) && (nPRE~=Ncol)
error('CVARGAS:saveascii:incorrectFmtLongInput',...
'Precision FMT vector must have 1 or Ncol integers.')
end
% Checks integer:
if any(~isnatural(numopt{1}))
error('CVARGAS:saveascii:notIntegerFmtInput',...
'Precision FMT must be integers.')
end
% Forces integers and row vector:
PRE = numopt{1}(:).';
function FMT = pre2fmt(PRE,WID,SPC,Ncol,x3)
% Calculates the width for each column and creates the format string for
% each column with that width, precision and delimiter.
% Reduce the size of x3 if a single precision is given.
if length(PRE)==1
x3 = [max(x3(1,:)); any(x3(2,:),2)-2*any(x3(2,:)<0,2); min(x3(3,:))];
end
if isempty(WID)
WID = get_wid(PRE,x3([1 3],:));
% Check at least 3 digits when NaN's or INF's:
isbad = logical(x3(2,:));
isbad(isbad) = (WID(isbad)<=3);
WID(isbad) = 3 + any(x3(2,isbad)<0,1);
% Converst from numeric format to format string:
end
FMT = pre2fmtcol(PRE,WID,SPC,Ncol);
function FMT = pre2fmtcol(PRE,WID,SPC,Ncol)
% Creates the format string for each (or every) column from precision,
% width and specifier.
% Added to reduce running time by reducing the usage of INT2STR. Feb 2008
[w,w,iw] = unique(WID);
[p,p,ip] = unique(PRE);
Nw = length(w);
Np = length(p);
Sw = cell(1,Nw);
Sp = cell(1,Np);
for k = 1:Nw
Sw{k} = int2str(WID(w(k)));
end
for k = 1:Np
Sp{k} = int2str(PRE(p(k)));
end
% Checks flag on specifier:
if length(SPC)==2
flag = SPC(1);
SPC(1) = [];
else
flag = '';
end
% Writes the format strings:
FMT = cell(1,1+(Ncol-1)*(Nw*Np~=1));
FMT{1} = ['%' flag Sw{iw(1)} '.' Sp{ip(1)} SPC];
if Nw*Np~=1
for k = 2:Ncol
FMT{k} = [ '%' flag Sw{iw(k)} '.' Sp{ip(k)} SPC];
end
end
function WID = get_wid(PRE,x)
% Calculates the maximum number of digits for each (or every) column of x.
M = get_order(x);
M(M<0) = 0; % M=0 if 00);
% If NaN, InF or -Inf sets at least 3, 3 or 4 digits respectively.
isbad = any(~isfinite(x),1);
isbad(isbad) = (WID(isbad)<=3) | ~isfinite(WID(isbad));
WID(isbad) = 3 + any(x(:,isbad)<0,1);
function [DLM,FMT,EOEL,full] = get_cell(DLM,FMT,EOEL,Ncol,cellopt)
% Reads cell optional inputs.
% Initializes.
nDLM = 0;
nFMT = double(~isempty(FMT));
full = false;
while ~isempty(cellopt)
n = length(cellopt{1});
ind = regexp([' ' cellopt{1}{1} ' '],'[^%]%[^%]');
m = length(ind);
if (n==1 ) && ((m~=0) && (((m==1) || (m==Ncol)) || (Ncol==0)))
% FMT for every column.
FMT = cellopt{1}; nFMT = nFMT+1;
full = (m==Ncol);
elseif (m==1) && ((n~=0) && ((n==Ncol) || (Ncol==0)))
% FMT for each column.
for k = 2:Ncol
% Checks if all of them are formats.
ind = regexp([' ' cellopt{1}{k} ' '],'[^%]%[^%]');
if length(ind)~=1
error('CVARGAS:saveascii:incorrectFmtCellInput',...
'Incorrect FMT cell of strings input.')
end
end
FMT = cellopt{1}; nFMT = nFMT+1;
elseif (n==1) && (m==0)
% DLM for every column.
DLM = cellopt{1}; nDLM = nDLM+1;
elseif (m==0) && ((n==(Ncol-1)) || (Ncol==0))
% DLM for each column.
DLM = cellopt{1}; nDLM = nDLM+1;
else
if m==0
error('CVARGAS:saveascii:incorrectCellLengthInput',...
'DLM cell of string must be of length 1 or Ncol-1.')
else
error('CVARGAS:saveascii:incorrectFmtLengthInput',...
'FMT cell of string must be of length 1 or Ncol.')
end
end
cellopt(1) = [];
end
% Checks for errors:
if nDLM>1
error('CVARGAS:saveascii:tooManyDlmInput',...
'More than one DLM given.')
end
if nFMT>1
error('CVARGAS:saveascii:tooManyFmtInput',...
'More than one FMT given.')
end
% Checks ending of full format:
if full && (length(FMT{1})>1) && (strcmp(FMT{1}(end-1:end),'\n') || ...
strcmp(FMT{1}(end-1:end),'\r'))
EOEL = '';
end
function [FILE,PER,TOB,WAR,DLM,FMT,EOEL,full] = ...
get_char(FILE,PER,TOB,WAR,DLM,FMT,EOEL,Ncol,stropt,ichar)
% Reads string optional inputs.
% Initializes.
nFILE = double(~isempty(FILE));
nPER = 0;
nDLM = ~isempty(DLM);
nFMT = double(~isempty(FMT));
full = false;
% Checks strings inputs
while ~isempty(stropt)
% Looks for '%' chars.
ind = regexp([' ' stropt{1} ' '],'[^%]%[^%]');
m = length(ind);
if m~=0 && (((m==1) || (m==Ncol)) || (Ncol==0))
% Sets FMT:
FMT = stropt(1); nFMT = nFMT+1;
full = (m==Ncol);
else
% Looks for PER or FILE:
switch stropt{1}
case {'w','a'}
PER = stropt{1}; nPER = nPER+1;
case {'wt','at','wb','ab'}
PER = stropt{1}(1); nPER = nPER+1;
TOB = stropt{1}(2);
case {'w -i'}
PER = stropt{1}(1); nPER = nPER+1;
WAR = true;
case {'wt -i','wb -i'}
PER = stropt{1}(1); nPER = nPER+1;
TOB = stropt{1}(2);
WAR = true;
otherwise
if ichar(1)==1
FILE = stropt{1}; nFILE = nFILE+1;
else
if nDLM
error('CVARGAS:saveascii:incorrectCharInput', ...
['Incorrect char input. \n\n' ...
'Must be a valid OPEN MODE (''a'',''w'') or a valid FILE NAME ' ...
'(as second input). '])
end
DLM = {stropt{1}};
end
end
end
stropt(1) = [];
ichar(1) = [];
end
% Checks for errors:
if nFILE>1
error('CVARGAS:saveascii:tooManyFileInput',...
'More than one FILE given.')
end
if nPER>1
error('CVARGAS:saveascii:tooManyPermissionsInput',...
'More than one open file permission given.')
end
if nFMT>1
error('CVARGAS:saveascii:tooManyFmtInput',...
'More than one FMT given.')
end
if (nPER==1) && (nFILE==0)
warning('CVARGAS:saveascii:ignoredPermissionInput',...
'Ignored Permission input because no FILE given.')
end
% Checks ending of full format:
if full && (length(FMT{1})>1) && (strcmp(FMT{1}(end-1:end),'\n') || ...
strcmp(FMT{1}(end-1:end),'\r'))
EOEL = '';
end
function FULLFMT = get_strform(DLM,FMT,Ncol)
% Generates the whole format string from the options or defaults.
FULLFMT = '';
Nf = length(FMT);
% a) Super format:
if Nf==1
Nf = numel(strfind(FMT{1},'%'));
if Nf==Ncol
FULLFMT = FMT{1};
elseif Nf~=1 % Error in the full format string option.
error('CVARGAS:saveascii:invalidStrOptionsSize',...
'Number of format strings must be 0, 1 or Ncol.')
end
end
% b) Piecewise format:
if isempty(FULLFMT)
FULLFMT = FMT{1};
Nd = length(DLM);
if Nd==1 % Single delimiter?
if Nf==1 % + single format?
FULLFMT = [FULLFMT repmat([DLM{1} FMT{1}],1,Ncol-1)];
else % + Ncol formats?
for k = 2:Ncol
FULLFMT = [FULLFMT DLM{1} FMT{k}];
end
end
elseif Nd==(Ncol-1) % Ncol-1 delimiters?
if Nf==1 % + single format?
for k = 2:Ncol
FULLFMT = [FULLFMT DLM{k-1} FMT{1}];
end
else % + Ncol formats?
for k = 2:Ncol
FULLFMT = [FULLFMT DLM{k-1} FMT{k}];
end
end
else % No delimiters (all failed)
if Nf==1 % + single format?
FULLFMT = repmat(FULLFMT,1,Ncol);
else % + Ncol formats?
for k = 2:Ncol
FULLFMT = [FULLFMT FMT{k}];
end
end
end
end
function M = get_order(x)
% Gets the order of magnitud in 10 base, i.e., in scientific notation:
% M = get_order(y) => y = X.XXXXXX x 10^M
if isinteger(x) % Allows integer input: uint8, etc.
x = double(x); % bug fixed Mar 08
end
temp = warning('off','MATLAB:log:logOfZero');
M = floor(log10(abs(x))); % In cientific notation x = XXX x 10^M.
M(x==0) = 0; % M=0 if x=0. (Bug fixed 10/jan/2008) (bug fixed 05/may/2008)
warning(temp.state,'MATLAB:log:logOfZero')
function y = maxinf(x,varargin)
%MAXINF Largest component ignoring INF's as posible.
%
% Y = MAXINF(X) is equivalent to MAX but ignoring INF's. If there is no
% finite elements, then the INF or -INF value is returned; NaN's are
% return if all the elements are NaN's.
y = max(x,varargin{:});
iinf = isinf(y);
if any(iinf(:))
xinf = y(iinf);
x(~isfinite(x)) = NaN;
y = max(x,varargin{:});
inan = isnan(y(iinf));
if any(inan(:))
y(iinf(inan)) = xinf(inan);
end
end
function y = mininf(x,varargin)
%MININF Smallest component ignoring -INF's as posible.
%
% Y = MININF(X) is equivalent to MIN but ignoring -INF's. If there is no
% finite elements, then the INF or -INF value is returned; NaN's are
% return if all the elements are NaN's.
y = min(x,varargin{:});
iinf = isinf(y);
if any(iinf(:))
xinf = y(iinf);
x(~isfinite(x)) = NaN;
y = min(x,varargin{:});
inan = isnan(y(iinf));
if any(inan(:))
y(iinf(inan)) = xinf(inan);
end
end
function n = isnatural(n)
%ISNATURAL Checks if an array has natural numbers.
% Y = ISNATURAL(X) returns a logical array of the same size as X with
% ones in the elements of X that are natural numbers
% (...-2,-1,0,1,2,...), and zeros where not.
% Written by
% M.S. Carlos Adrián Vargas Aguilera
% Physical Oceanography PhD candidate
% CICESE
% Mexico, November 2006
%
% nubeobscura@hotmail.com
n = (n==floor(n)) & isreal(n) & isnumeric(n) & isfinite(n);
% [EOF] saveascii.m