function varargout = evalf(varargin)
%EVALF Evaluates specified function in specified directory if required.
%
% SYNTAX:
% evalf(FUNC)
% evalf(FUNC,ARG1,ARG2,ARG3,...)
% evalf('-there',...)
% evalf('-DIR',...)
% [OUT1,OUT2,...] = evalf(...);
%
% INPUT:
% FUNC - Unique MATLAB function/script handle, anonymous handle,
% file name or full-name to be evaluated.
% ARG1,... - Comma separated input argument(s) of the function FUNC.
% DEFAULT: (non inputs)
% '-there' - Evaluates FUNC in the directory it is located, returning
% to the current one when is done.
% DEFAULT: '-here' ('-there' if FUNC is a fullname)
% '-DIR' - Evaluates FUNC in the specified directory as momentarily
% current. For example: '-C:\MATLAB'.
% DEFAULT: ['-' pwd] (or the specified on full-name)
%
% OUTPUT:
% OUT1,... - Comma separated output argument(s) of FUNC.
% DEFAULT: (none)
%
% DESCRIPTION:
% MATLAB evaluates functions and scripts located only on the Current
% Directory (see PWD) or its list of directories (see PATH). This
% function allows the user to run any MATLAB function located in any
% location (specified by its full-name).
%
% Besides, while evaluating the function the Current Directory may be
% changed to the one specified on the full-name, or the one by
% '-DIR'.
%
% Another important difference from MATLAB's FEVAL function, is that
% this function works correctly with anonymous function handles. In
% fact, functions given by name (strings) are converted into a function
% handle.
%
% Variables defined on M-files scripts are returned in the MATLAB
% workspace ('base').
%
% NOTE:
% * Optional inputs use its DEFAULT value when not given or [].
% * Optional outputs may or not be called.
% * Only '-t' and '-h' are considered, instead of '-there' and '-here'.
% * ADDITIONAL NOTES are included inside this file.
%
% EXAMPLE:
% x = linspace(0,4*pi);
% y = sin(x);
% % 1) Function and inputs versatility:
% hold on
% % By function name:
% evalf('plot',x,y,'b*')
% % By handle function:
% evalf(@plot,x,y,'ro');
% % By anonymous handle function:
% evalf(@(z)plot(x,z,'g'),y);
% hold off
% legend('''plot''','@plot','@(z)plot(x,z,''g'')')
% % 2) Multiple outputs versatility:
% [vmax,imax] = evalf('max',[10 20 30 40 30 20 10])
% % 3) Directories versatility:
% % i) Evaluates "LS" MATLAB function on Current Directory:
% disp('i)')
% evalf ls
% % ii) Evaluates LS on previous directory:
% disp('ii)')
% evalf -.. ls
% % iii) Evaluates in its directory:
% disp('ii)')
% evalf([matlabroot '\toolbox\matlab\general\ls'])
% In i) and ii) LS must be on MATLAB PATH.
%
% SEE ALSO:
% FEVAL, EVALIN, RUN, PATH, PWD
% and
% FUNC2FUNC by Carlos Vargas
% at http://www.mathworks.com/matlabcentral/fileexchange
%
%
% ---
% MFILE: evalf.m
% VERSION: 2.0 (Sep 21, 2009) (<a href="matlab:web('http://www.mathworks.com/matlabcentral/fileexchange/authors/11258')">download</a>)
% MATLAB: 7.7.0.471 (R2008b)
% AUTHOR: Carlos Adrian Vargas Aguilera (MEXICO)
% CONTACT: nubeobscura@hotmail.com
% ADDITIONAL NOTES:
% * In order to make the function compatible with previous MATLAB
% releases (although I couldn't test this), I avoided the use of some
% functions like FILESEP, RETHROW, STRCMPI, SWITCH-CASE short-circuit
% logicals, etc. I don't know if the TRY-CATCH is new, anyway I try
% to avoid it too. If there is some problem just let me know to make
% the appropiate changes. With VARARGIN, VARARGOUT, NARGIN and
% NARGOUT I cannot do too much. By the way, I don't know if ERROR and
% EXIST allow 2 inputs in previous releases.
% REVISIONS:
% 1.0 Released (Nov 10, 2008)
% 2.0 Fixed bug with reading name file and extension. Now works with
% scripts. (Sep 21, 2009)
% Copyright 2008,2009 Carlos Adrian Vargas Aguilera
% INPUTS CHECK-IN
% -------------------------------------------------------------------------
% Sets defaults.
dothere = NaN;
DIR = [];
% Sets parameters.
currDir = cd; % Current Directory.
sep = findstr(currDir,'\'); % NOTE: I avoided the use of FILESEP.
if ~isempty(sep)
sep = '\'; % Windows
else
sep = '/'; % Linux
end
if ~strcmp(currDir(end),sep), currDir = [currDir sep]; end
iscript = false; % SCRIPT file instead of function.
% Checks number of inputs.
if (nargin<1)
error('CVARGAS:evalf:notEnoughInputs', ...
'No function was specified.')
end
% Checks number of outputs.
if (nargout~=0)
varargout = cell(nargout,1);
end
% Checks '-t' or '-h' or '-DIR' input.
if ischar(varargin{1})
if isempty(varargin{1})
error('CVARGAS:evalf:incorrectFirstInput',...
'First input cannot be empty.')
elseif strcmp(varargin{1}(1),'-')
% NOTE: I avoided the use of SWITCH-CASE.
if length(varargin{1})==1
error('CVARGAS:evalf:incorrectOptionalInput',...
'Optional first input must be ''-t'', ''-h'' or a valid ''-DIR''.')
elseif strcmp(lower(varargin{1}(2)),'t')
% '-there'.
dothere = true;
varargin(1) = [];
elseif strcmp(lower(varargin{1}(2)),'h')
% '-here'.
dothere = false;
varargin(1) = [];
else
% '-DIR'.
% NOTE: I avoided the use of short-circuit logical: ||.
DIR = varargin{1}(2:end);
if ~strcmp(DIR(end),sep), DIR = [DIR sep]; end
if strcmp(lower(DIR),lower(currDir))
DIR = [];
elseif strcmp(DIR,['.' sep])
DIR = [];
elseif ~(exist(DIR,'dir')==7)
error('CVARGAS:evalf:incorrectOptionalInput',...
'Optional first input must be ''-t'', ''-h'' or a valid ''-DIR''.')
else
dothere = true;
end
varargin(1) = [];
end
end
% Checks if any input was left.
if isempty(varargin)
error('CVARGAS:evalf:notEnoughInputs',...
'No function was specified.')
end
end
% Checks FUNC input.
FUNC = varargin{1};
varargin(1) = [];
if isempty(FUNC)
error('CVARGAS:evalf:notEnoughInputs',...
'No function was specified.')
elseif ischar(FUNC)
% Function name.
% Looks if the function exist on its specified direction or, if not
% specified, in the Current Directory or PATH.
% NOTE: I avoided the use of ISMEMBER.
if ~(exist(FUNC,'file')==2)
if ~(exist(FUNC,'builtin')==5)
% Adds extra '\' and '%' chars to be printed on error display.
ind1 = findstr(FUNC,'\');
if ~isempty(ind1)
N = length(FUNC);
ind2 = zeros(1,N);
ind2(ind1) = 1;
temp( ind1+cumsum(ind2(ind1))-1) = '\';
temp((1:N)+cumsum(ind2)) = FUNC;
FUNC = temp;
end
ind1 = findstr(FUNC,'%');
if ~isempty(ind1)
N = length(FUNC);
ind2 = zeros(1,N);
ind2(ind1) = 1;
temp( ind1+cumsum(ind2(ind1))-1) = '%';
temp((1:N)+cumsum(ind2)) = FUNC;
FUNC = temp;
end
error('CVARGAS:evalf:incorrectFuncInput', ...
['The function ''' FUNC ''' was not found.'])
end
end
% Gets funcDir, funcNam and funcExt manually.
% NOTE: I avoided the use of FILEPARTS.
indsep = findstr(FUNC,sep);
if isempty(indsep)
indsep = 0;
funcDir = [];
else
indsep = indsep(end);
funcDir = FUNC(1:indsep);
end
indext = findstr(FUNC(indsep+1:end),'.');
if isempty(indext)
indext = length(FUNC)-indsep+1;
funcExt = [];
else
indext = indext(end);
funcExt = FUNC(indsep+indext:end); % Fixed bug, Sep 2009
end
funcNam = FUNC(indsep+(1:indext-1)); % Fixed bug, Sep 2009
% Checks funcExt.
if ~isempty(funcExt)
% NOTE: I avoided the use of SWITCH-CASE.
if strcmp(lower(funcExt),'.m')
% Checks if function or script, Sep 2009
fid = fopen(FUNC);
while 1
tline = fgetl(fid);
if ~ischar(tline), break, end
tline = fliplr(deblank(fliplr(tline)));
if isempty(tline), continue, end
if ~strcmp(tline(1),'%')
if length(tline)>9
if strcmp(tline(1:9),'function ')
break
end
end
end
iscript = true;
end
fclose(fid);
if iscript
if nargout | ~isempty(varargin)
error('CVARGAS:evalf:noOutputsInputsOnScripts',...
'Scripts files cannot have inputs/outputs.')
end
end
elseif strcmp(lower(funcExt),'.p')
% continue
else
error('CVARGAS:evalf:incorrectFileExtension',...
'Function must be an M- or P-file.')
end
end
% Checks funcDir.
if ~isempty(funcDir)
if isnan(dothere)
dothere = true;
end
if dothere
DIR = funcDir;
end
end
% Gets the function handle.
if (exist('str2func','builtin')==5)
FUNC = str2func(funcNam);
else
FUNC = feval(['@' funcNam]);
end
elseif isa(FUNC,'function_handle')
% Function handle.
% Just get the function name and dir.
if exist('func2str','builtin')==5
funcNam = func2str(FUNC);
else
funcNam = [];
end
funcDir = '';
else
error('CVARGAS:evalf:incorrectFuncInput',...
'FUNC must be a function name, handle or anonymous handle.')
end
% -------------------------------------------------------------------------
% MAIN
% -------------------------------------------------------------------------
% Go to evaluation directory.
if ~isempty(DIR)
if strcmp(lower(DIR),lower(currDir)) | strcmp(DIR,['.' sep])
DIR = [];
dothere = false;
end
end
if ~dothere
% Evaluates on Current Directory.
currDir = [];
else
% Evaluates on DIR.
cd(DIR)
end
% Evaluation.
if (exist('try','builtin')==5)
% Tries to evaluate in given directory, catching any error during
% evaluation to be able to return to previous Current Directory.
try
if nargout==0
if iscript % Sep 2009
% Uses EVALIN to export any variable definition on the function to the
% MATLAB workspace intead of the workspace of this function.
evalin('base',funcNam)
else
FUNC(varargin{:})
end
else
[varargout{:}] = FUNC(varargin{:});
end
catch
if ~isempty(currDir)
cd(currDir)
end
if (exist('lasterror','builtin')==5)
message = lasterror;
message = message.message;
else
message = theerror;
end
error('CVARGAS:evalf:errorWhileEvauating',...
['Error during ' [funcDir funcNam] ' function evaluation. \n\n' ...
message])
end
else
if nargout==0
if iscript % Sep 2009
% Uses EVALIN to export any variable definition on the function to the
% MATLAB workspace intead of the workspace of this function.
evalin('base',funcNam)
else
FUNC(varargin{:})
end
else
[varargout{:}] = FUNC(varargin{:});
end
end
% Returns to previous directory.
if ~isempty(currDir)
cd(currDir)
end
% [EOF] evalf.m