function errorCode = mbuild(varargin)
%MBUILD Compile an executable from C source code.
%   MBUILD <options> <files> compiles an executable from C source code.
%   All non-source code file names passed as arguments are passed to the
%   linker without being compiled.
%
%   Available options on all platforms are:
%   -c               Compile only; do not link.
%   -D<name>[=<def>] Define C preprocessor macro name <name> [as having value
%                    <def> (assignment not available under Windows)].
%   -f <file>        Use <file> as the options file; <file> is a full path
%                    name if not in current directory. (Not necessary if you
%                    use the -setup option.)
%   -g               Build an executable with debugging symbols included.
%   -h[elp]          Help; print this message.
%   -I<pathname>     Include <pathname> in the Compiler include search path.
%   -lang <language> Override language choice implied by file extensions.
%                    <language> is either 'c' (for C) or 'cpp' (for C++).
%   -n               No execute flag. Using this option causes the commands
%                    that would be used to compile and link the target to be
%                    displayed without executing them.
%   -O               Build an optimized executable.
%   -output <name>   Create an executable named <name>. (An appropriate
%                    executable extension is automatically appended.)
%   -outdir <name>   Place all output files in directory <name>
%   -setup [optionsfile]
%                    Specify the Compiler options file to use as the
%                    default for future invocations of mbuild by
%                    placing it in $HOME/matlab. When this option is specified,
%                    no other command line input is accepted.
%   -U<name>         Undefine C preprocessor macro name <name>.
%   -v               Verbose; print all Compiler and linker settings.
%
%   On UNIX, the following additional options are available:
%   -l<file>         Link against library lib<file>.
%   -L<pathname>     Include <pathname> in the list of directories to search
%                    for libraries.
%   <name>=<def>     Override options file setting for variable <name>.
%
%   On Windows, the following additional options are available:
%   @<rsp_file>      Include contents of the text file <rsp_file> as
%                    command line arguments to MBUILD
%
%   MBUILD's execution is affected by both command-line arguments and
%   an options file.  The options file contains all Compiler-specific
%   information necessary to create an executable.  The name of this file
%   must be specified.
%
%   On UNIX, the options file is written in the Bourne shell script language.
%   Any variable specified in the options file can be overridden at the command
%   line by use of the <name>=<def> command line argument.  If <def> has
%   spaces in it, then it should be wrapped in single quotes
%   (e.g. CFLAGS='opt1 opt2').  The definition can rely on other variables
%   defined in the options file; in this case the referenced variable should
%   have a prepended "$" (e.g. CFLAGS='$CFLAGS opt2').
%
%   On Windows, the options file is written in the Perl script
%   language. No arguments can have an embedded equal sign ("="); thus,
%
%      -DFOO     is valid, but
%      -DFOO=BAR is not.

% $Revision: 1.16 $  $Date: 1998/12/03 16:29:26 $
% Copyright (c) 1984-1998 by The MathWorks, Inc.

global MBUILD_RETURN_RESULT_IN_ANS

c = computer;
if isunix
    
    errCode = unix([matlabroot '/bin/mbuild' sprintf(' %s', varargin{:})]);
    
elseif strncmp(c, 'PC', 2)
    
    [mexname, setup] = get_mex_opts(varargin{:});
    matlab_bin_location=[matlabroot '\bin'];
    if exist([matlab_bin_location '\nt\mex.bat'],'file') 
	matlab_bin_location=[matlabroot '\bin\nt'];
    end
    if (any(matlab_bin_location == ' '))
        matlab_bin_location = ['"' matlab_bin_location '"'];
    end

    if setup
        dos([matlab_bin_location '\mbuild.bat -setup&']);
        return;
    else
        % Loop over all the arguments. Put extra quotes around any that
        % contain spaces.
        
        for i=1:prod(size(varargin))
            if (find(varargin{i} == ' '))
                varargin{i} = [ '"' varargin{i} '"' ];
            end
        end

        eval(['!' matlab_bin_location '\mbuild.bat -called_from_matlab' sprintf(' %s', varargin{:})]);
        errCode = 0; % success
    end

elseif ~strcmp(c(1:2), 'MA')
    error(['Unknown platform: ' c]);
    
else % Macintosh:
    varargin{end + 1} = '-mbuild';
    errCode = mex(varargin{:});
    
end

if (nargout > 0) | (~isempty(MBUILD_RETURN_RESULT_IN_ANS)  & ...
        MBUILD_RETURN_RESULT_IN_ANS)
    errorCode = errCode;
elseif (errCode ~= 0)
    error('Unable to complete successfully');
end


%%%%%%%%%%%%%%%%%%%%
%%% SUBFUNCTIONS %%%
%%%%%%%%%%%%%%%%%%%%

function result = read_response_file(filename)
%
% Read a response file (a filename that starts with '@')
% and return a cell of strings, one per entry in the response file.
% Use Perl to ensure processing of arguments is the same as mex.bat
%

matlab_bin_location=[matlabroot '\bin'];
if exist([matlab_bin_location '\nt\mex.bat'],'file') 
    matlab_bin_location=[matlabroot '\bin\nt'];
end

result = {};

cmd = ['"'matlab_bin_location '\perl" -e "' ...
    'require ''' matlab_bin_location '\\perl\\lib\\shellwords.pl'';' ...
    'open(FILE, ''' filename ''') || die ''Could not open ' filename ''';' ...
    'while (<FILE>) {$line .= $_;} ' ...
    '$line =~ s/\\/\\\\/g;' ...
    '@ARGS = &shellwords($line); ' ...
    '$\" = \"\n\";' ...
    'print \"@ARGS\";'];

[s, r] = dos(cmd);

if s == 0
    cr = sprintf('\n');
    while ~isempty(r)
        [result{end+1}, r] = strtok(r, cr);
    end
end

function [mexname, setup] = get_mex_opts(varargin)
%
% GET_MEX_OPTS gets the options from the command line.
%
% name:
% It gets the name of the destination MEX-file.  This has two
% purposes: 
%   1) All platforms need to clear the MEX-file from memory before
%      attempting the build, to avoid problems rebuilding shared
%      libraries that the OS considers "in use".
%   2) Windows MATLAB deletes the MEX-file before the build occurs.
%      It then checks to see whether the MEX-file was created so as
%      to establish error status.
%   This function returns the minimum necessary information.  Further
%   processing is done on the MEX-file name by clear_mex_file to 
%   successfully clear it.
%
% setup:
% It also returns whether or not '-setup' was passed.
%

mexname = '';
outdir = '';
setup = 0;

% First, check for and expand response files into varargin.
v = {};
for count=1:nargin
    arg = varargin{count};
    if arg(1) == '@'
        new_args = read_response_file(arg(2:end));
        v(end+1:end+length(new_args)) = new_args;          
    else
        v{end+1} = arg;
    end
end

varargin = v;
nargin = length(varargin);

count = 1;
while (count <= nargin)
    arg = varargin{count};
    if isempty(mexname) & arg(1) ~= '-' & ~any(arg=='=') & any(arg=='.')
        %
        % Source file: MEX-file will be built in current directory
        % Only the first source file matters
        %
        mexname = arg;
        fileseps = find(mexname == filesep);
        if any(fileseps)
            mexname = mexname(fileseps(end)+1:end);
        end
        mexname = strtok(mexname, '.');
    elseif strcmp(arg, '-f')
        count = count + 1;
    elseif strcmp(arg, '-output')
        count = count + 1;
        if count > length(varargin)
            error('-output switch must be followed by a filename');
        end
        mexname = varargin{count};
    elseif strcmp(arg, '-outdir')
        count = count + 1;
        if count > length(varargin)
            error('-outdir switch must be followed by a directory name');
        end
        outdir = varargin{count};
    elseif strcmp(arg, '-setup')
        setup = 1;
        break;
    end
    count = count + 1;
end

mexname = fullfile(outdir, mexname);


