function savecsvdata(o,fname)

namerow = o.namerow;
dates = o.dates;
data = o.data;

if isfield(o,'commentrow')
    commentrow = o.commentrow;
else
    commentrow = {};
end
iscommentrow = ~isempty(commentrow);

if isfield(o,'classrow')
    classrow = o.classrow;
else
    classrow = {};
end
isclassrow = ~isempty(classrow);

if isfield(o,'unitrow')
    unitrow = o.unitrow;
else
    unitrow = {};
end
isunitrow = ~isempty(unitrow);

if isfield(o,'nanstring')
    nanstring = o.nanstring;
else
    nanstring = 'NaN';
end
isnanstring = ~strcmpi(nanstring,'NaN');

if isfield(o,'format')
    format = o.format;
else
    format = '%.8e';
end

if isfield(o,'highlight')
    highlight = o.highlight;
else
    highlight = [];
end
ishighlight = ~isempty(highlight);

isuserdata = isfield(o,'userdata');

%**************************************************************************

% Create an empty buffer.
c = '';
br = sprintf('\n');

% Write database user data.
if isuserdata
    userdata = utils.any2str(o.userdata);
    userdata = strrep(userdata,'"','''');
    c = [c,'"Userdata[',o.userdatafieldname,'] ->","',userdata,'"',br];
end

% Write name row.
if ishighlight
    namerow = [{''},namerow];
end
c = [c,'"Variables ->"',xxprintcharcells(namerow)];

% Write comments.
if iscommentrow
    if ishighlight
        commentrow = [{''},commentrow];
    end
    c = [c,br,'"Comments ->"',xxprintcharcells(commentrow)];
end

% Write units.
if isunitrow
    if ishighlight
        unitrow = [{''},unitrow];
    end
    c = [c,br,'"Units ->"',xxprintcharcells(unitrow)];
end

% Write classes.
if isclassrow
    if ishighlight
        classrow = [{''},classrow];
    end
    c = [c,br,'"Class[Size] ->"',xxprintcharcells(classrow)];
end

% Create cellstr with date strings.
ndates = length(dates);

% Handle escape characters.
dates = strrep(dates,'\','\\');
dates = strrep(dates,'%','%%');

% Create format string fot the imaginary parts of data; they need to be
% always printed with a plus or minus sign.
iformat = [format,'i'];
if isempty(strfind(iformat,'%+')) && isempty(strfind(iformat,'%0+'))
    iformat = strrep(iformat,'%','%+');
end

% Find columns that have at least one non-zero imag. These column will
% be printed as complex numbers.
nrow = size(data,1);
ncol = size(data,2);
% Combine real and imag columns in an extended data matrix.
xdata = zeros(nrow,2*ncol);
xdata(:,1:2:end) = real(data);
idata = imag(data);
xdata(:,2:2:end) = idata;
% Find imag columns and create positions of zero-only imag columns that
% will be removed.
icol = any(idata ~= 0,1);
removecol = 2*(1 : ncol);
removecol(icol) = [];
% Check for the occurence of imaginary NaNs.
isimagnan = any(isnan(idata(:)));
% Remove zero-only imag columns from the extended data matrix.
xdata(:,removecol) = [];
% Create a sequence of formats for one line.
formatline = cell(1,ncol);
% Format string for columns that have imaginary numbers.
formatline(icol) = {[',',format,iformat]};
% Format string for columns that only have real numbers.
formatline(~icol) = {[',',format]};
formatline = [formatline{:}];

% We must create a format line for each date because the date strings
% vary.
br = sprintf('\n');
formatdata = '';
for i = 1 : size(data,1)
    if i <= ndates
        thisdate = ['"',dates{i},'"'];
    else
        thisdate = '"NaN"';
    end
    if ishighlight
        if i <= ndates && highlight(i)
            thisdate = [thisdate,',"***"']; %#ok<AGROW>
        else
            thisdate = [thisdate,',""']; %#ok<AGROW>
        end
    end
    formatdata = [formatdata,br,thisdate,formatline]; %#ok<AGROW>
end
cc = sprintf(formatdata,xdata.');

% NaNi is never printed with the leading sign. Replace NaNi with +NaNi. We
% should also control for the occurence of NaNi in date strings but we
% don't as this is quite unlikely (and would not be easy).
if isimagnan
    cc = strrep(cc,'NaNi','+NaNi');
end

% Replace NaNs in the date/data matrix with a user-supplied string. We
% don't protect NaNs in date strings; these too will be replaced.
if isnanstring
    cc = strrep(cc,'NaN',nanstring);
end

% Splice the headings and the data, and save the buffer. No need to put
% a line break between `c` and `cc` because that the `cc` does start
% with a line break.
char2file([c,cc],fname);

end

% Subfunctions.

%**************************************************************************
function s = xxprintcharcells(c)

s = '';
if isempty(c) || ~iscellstr(c)
    return
end
s = sprintf(',"%s"',c{:});

end
% xxprintcharcells().