function s = latex(M,varargin)
%LATEX   Print a matrix in LaTeX tabular format.
%   LATEX(M) prints out the numeric matrix M in a LaTeX tabular
%   format. The '&' character appears between entries in a row, '\\'
%   is appended to the ends of rows, and each entry is set in math
%   mode. Complex numbers are understood, and exponentials will be
%   converted to a suitable format.
%
%   LATEX(M,'nomath') does not include the $$ needed to put each 
%   entry in math mode (e.g., for use with the amsmath matrix modes).
%   
%   LATEX(M,FMT) uses a format specifier FMT of the SPRINTF type for
%   each entry.
%   
%   LATEX(M,FMT1,FMT2,...) works through the given format specifiers
%   on each row of M. If fewer are given than the column size of M,
%   the last is used repeatedly for the rest of the row.
%   
%   S = LATEX(M,...) does not display output but returns a character
%   array S.
%   
%   Examples:
%     latex( magic(4) )
%     latex( magic(4), '%i', 'nomath' )
%     latex( magic(4), '%i', '%.2f' )
%   
%   See also SPRINTF, SYM/LATEX.

%   Copyright 2002 by Toby Driscoll. Last updated 12/06/02.

if ~isa(M,'double')
  error('Works only for arrays of numbers.')
elseif ndims(M) > 2
  error('Works only for 2D arrays.')
end

if nargin < 2
  fmt = {'%#.5g'};
  mathstr = '$';
else
  fmt = varargin;
  idx = strmatch('nomath',fmt);
  if isempty(idx)
    mathstr = '$';
  else  
    mathstr = '';
    fmt = fmt([1:idx-1 idx+1:end]);
    if isempty(fmt), fmt = {'%#.5g'}; end
  end 
end

% Extend the format specifiers.
[m,n] = size(M);
if n > length(fmt)
  [fmt{end:n}] = deal(fmt{end});
end
  
% Create one format for a row.
rowfmt = '';
for p = 1:n
  % Remove blanks.
  thisfmt = deblank(fmt{p});

  % Add on imaginary part if needed.
  if ~isreal(M(:,p)) 
    % Use the same format as for the real part, but force a + sign for
    % positive numbers. 
    ifmt = thisfmt;
    j = findstr(ifmt,'%');
    if ~any(strcmp(ifmt(j+1),['-';'+';' ';'#']))
      ifmt = [ifmt(1:j) '+' ifmt(j+1:end)];
    else
      ifmt(j+1) = '+';
    end
    ifmt = [ifmt 'i'];
    thisfmt = [thisfmt ifmt];
  end

  % Add to row.
  rowfmt = [rowfmt mathstr thisfmt mathstr ' & '];
end

% After last column, remove column separator and put in newline.
rowfmt(end-1:end) = [];
rowfmt = [rowfmt '\\\\\n'];

% Use it.
A = M.';
if isreal(M)
  S = sprintf(rowfmt,A);
else
  S = sprintf(rowfmt,[real(A(:)) imag(A(:))].');
end

% Remove extraneous imaginary part for real entries.
if ~isreal(M)
  zi = sprintf(ifmt,0);
  S = strrep(S,zi,blanks(length(zi)));
end

% Remove NaNs.
S = strrep(S,'$NaN$','--');
S = strrep(S,'NaN','--');

% Convert 'e' exponents to LaTeX form. This is probably really slow, but
% what can you do without regular expressions?
S = strrep(S,'e','E');
ex = min(findstr(S,'E'));
while ~isempty(ex)
  % Find first non-digit character. Where is ISDIGIT?
  j = ex+2;
  while ~isempty(str2num(S(j))) & ~strcmp(S(j),'i')
    j = j+1;
  end

  % This strips off leading '+' and zeros.
  num = sprintf('%i',str2num(S(ex+1:j-1)));
  
  ee = ['\times 10^{' num '}'];
  S = [S(1:ex-1) ee S(j:end)];
  
  ex = ex + min(findstr(S(ex+1:end),'E'));
end

% For good form, remove that last '\\'.
S(end-2:end-1) = '  ';

% Display or output?
if nargout==0
  disp(S)
else
  s = S;
end
