function [trace_list, builtins, class_names, prob_files, prob_symbols,  ...
		eval_strings, calledfrom, java_classes] = depfun(varargin)
%DEPFUN  Locate dependent functions of an m/p-file.
%    TRACE_LIST = DEPFUN(FUN) returns a cell array of names of the dependent
%    functions of FUN.  FUN is directly dependent on the functions that it
%    calls; FUN is indirectly dependent on the functions called by the 
%    functions called by FUN, and so on. 
%
%    [TRACE_LIST, BUILTINS, CLASS_NAMES] = DEPFUN(FUN) also returns a 
%    cell array of all builtin functions and MATLAB classes called by FUN 
%    and its dependent functions.
%
%    The syntax for DEPFUN with all possible outputs is:
%    [TRACE_LIST, BUILTINS, CLASS_NAMES, PROB_FILES, PROB_SYMBOLS,...
%                EVAL_STRINGS, CALLED_FROM, JAVA_CLASSES] = DEPFUN(FUN)
%    where:
%    PROB_FILES is a structure array of m/p-files that DEPFUN could not parse,
%      locate, or access.  Parsing problems can arise from MATLAB syntax errors.
%    PROB_SYMBOLS is a structure array that indicates which symbol names DEPFUN
%      could not resolve as functions or variables. 
%    EVAL_STRINGS is a structure array that indicates where functions in
%      TRACE_LIST call eval, evalc, evalin, or feval. The strings that eval and 
%      similar functions evaluate might use functions that are not in TRACE_LIST.
%    CALLED_FROM is a cell array that indicates who calls whom.  CALLED_FROM
%      is arranged so that TRACE_LIST(CALLED_FROM{i}) lists all functions in FUN
%      that call TRACE_LIST{i}.  CALLED_FROM and TRACE_LIST have the same length.
%    JAVA_CLASSES is a cell array of Java class names used by one or more of the
%      files in TRACE_LIST.
%
%    [...] = DEPFUN(FILE1,FILE2,...) processes each file in turn.
%
%    [...] = DEPFUN(FIG_FILE) looks for dependent functions among the
%    callback strings of any GUI elements defined in the .FIG (or
%    .MAT) file FIG_FILE.
%
%    DEPFUN has optional control input strings.  The control parameter '-toponly' 
%    will override the default recursive search for dependent files and means 
%    DEPFUN will return lists of builtins, M/P/MEX-files, and classes used only 
%    in the functions listed as inputs to DEPFUN.  The control parameter
%    '-nographics' forces DEPFUN to only include graphics functions that are
%    explicitly called.  Normally DEPFUN, at a minimum, adds newplot to the 
%    function list.
%
%    Note: DEPFUN frequently writes temporary M-files to the TEMP
%    directory.  During this process the temporary directory is added to the 
%    MATLAB path.  Please try to ensure there are no M/P/MEX-files in this 
%    directory.
%
%    If you use any toolbar items from the default figure, then you
%    need to include 'FigureToolBar.fig' in your input to DEPFUN.  If you
%    use any menu items from the default figure, then you must include
%    'FigureMenuBar.fig' in your input to DEPFUN.
%
%    See also DEPDIR.

%    Copyright 1984-2000 The MathWorks, Inc. 
%    $Revision: 1.41 $ $Date: 2000/08/15 13:55:03 $

% check if there is the optional input flag that indicate we're not doing a recursive
% search
toponly = 0;  nographics = 0; newvarargin = {};
for i=1:length(varargin)
    if isstr(varargin{i})  &  strcmp(varargin{i},'-toponly')
        toponly = i;
    end
    if isstr(varargin{i})  &  strcmp(varargin{i},'-nographics')
        nographics = i;
    end
end
if toponly, varargin{toponly} = []; end
if nographics, varargin{nographics} = []; end

for i = 1:length(varargin)
  if ~isempty(varargin{i})
    newvarargin{end+1} = varargin{i};
  end
end
varargin = newvarargin;

if isempty(varargin), error('Not enough input arguments.'); end

% check for valid input
trace_list = {};
nin = length(varargin);
for i=1:nin
    if ~isstr(varargin{i})
        error('Input must be strings.');
    end
    % make sure start_name is a full path name
    [path, fname, extension] = fileparts(varargin{i});
    if isempty(extension)
        if exist(path,'dir')
            % have full path and name but no extension
            if exist([varargin{i} '.m'])
                extension = '.m';
            elseif exist([varargin{i} mexext])
                extension = mexext;
            elseif exist([varargin{i} '.p'])
                extension = 'p';
            else
                error(['File ' varargin{i} ' cannot be located or is not an ' ...
                        'M/MEX/P file.']);
            end
            trace_list{end+1} = [varargin{i} extension];
        else
        	fullname = which(varargin{i});
        	if ispc, extension = lower(extension); end
        	if isempty(fullname)
            	error(['Cannot locate file ' varargin{i} '.']);
        	end
        	if strcmp(fullname,'built-in')
            	fprintf('Function %s is a builtin and is being removed from search list\n',varargin{i});
        	else
            	trace_list{end+1} = fullname;
        	end
        end
    elseif exist(path,'dir')
        % got an extension and a full path
        trace_list(end+1) = varargin(i);
    elseif any(strcmp(extension,{'.m' '.p' '.fig' ['.' mexext]}))
        fullname = which(varargin{i});
        if isempty(fullname)
            error(['Cannot locate file ' varargin{i} '.']);
        end
        trace_list{end+1} = fullname;
    else
        error(['File ' varargin{i} ' is not an allowed file type (M/P/FIGS).']);  
    end
end

if isempty(trace_list)
    clear trace_list builtins class_names prob_files prob_symbols
    clear eval_strings calledfrom dyn_syms
    disp('DEPFUN inputs have no M-files to examine.');
	return
end

% Add newplot function to trace list as it's called indirectly
% for any graphics operation.
if ~toponly  &  ~nographics
	trace_list{end+1} = which('newplot');
	if strcmp(trace_list(end),'built-in'), trace_list(end) = []; end
end

% get handle graphics info
if ~toponly  &  ~nographics
	[hg_param, hg_val, cbparam, cbdef] = gethginfo;
	for i=1:length(cbdef)
 	   fname = which(cbdef{i});
    	if ~strcmp(fname,'built-in'), trace_list{end+1} = fname;  end
    end
else
    gethginfo('setup');
end

% Make sure tempdir is on the path
if isempty(findstr(tempdir,matlabpath))
  addpath(tempdir)
  added_temp = 1;
else
  added_temp = 0;
end

% Generate a temp m-file name that is used to hold evaluated strings
% for compilation.  Test temp file to verify it can be opened in write
% mode and deleted.  Unfortunately the delete command does not provide
% an error return value so I'm catching the warning and then erroring out.
lastwarn('');
tmpname = [tempname '.m'];
fid = fopen(tmpname, 'w');
fclose(fid);
if exist(tmpname), delete(tmpname); end
if strcmp(lastwarn,'File not found or permission denied')
    error(['Unable to run DEPFUN due to inability to write to and remove ' ...
            'temporary file (' tmpname ').']);
end

% Check for PC so we can do case insensitive file name comparisons
ispc = strncmp(computer,'PC',2);

prob_files = [];  fc = 0;  clas = {};
calledfrom(1:length(trace_list)) = {0};  prob_symbols = [];
script_id = []; eval_strings = []; which_psym = {};
del_prob_sym = {}; java_classes = {};

fsep = filesep;

% initialize builtin function list
if toponly
    builtins = {};
    which_builtins = [];
else
	builtins = {'subsindex' 'subsref' 'subsasgn' 'vertcat' 'horzcat'};
	which_builtins{length(builtins)} = [];
	for i=1:length(builtins)
    	meth = whichall(builtins{i});
    	if length(meth) > 1
			which_builtins{i} = meth;
        end
    end
end

% find currently visible classes
cls = classes;

% initialize which list that corresponds to trace list
which_trace_list{length(trace_list)} = [];
for i=1:length(trace_list)
    [path, fname, extension] = fileparts(trace_list{i});
    meth = whichall(fname);
    if length(meth) > 1
	% enter all methods except current file
	which_trace_list{i} = meth(~strcmp(meth,trace_list{i}));
    end
end

while fc < length(trace_list)
    fc = fc + 1;
    name = trace_list{fc};
    disp(['Examining file '  name]);

    % get path for file (either from name itself or which command)
    [path, fname, extension] = fileparts(name);
    if ispc, extension = lower(extension); end

    if strcmp(extension,'.m') | strcmp(extension,'.fig') | strcmp(extension,'.p')
	% attempt to get dependencies (failure indicates compile errors,
        % inaccessible file, or script)
        if strcmp(extension,'.m') | strcmp(extension,'.p')
            if strcmp(extension,'.m')
                matname = [name 'at'];
            else
                matname = [name(1:end-1) 'mat'];
            end
            if exist(matname)
                % A MAT-file that corresponds to the named m-file exists.  Load
                % data and pass to sniff function so it can get the HG callback
                % strings that potentially exist in the MAT-file.
                matdata = load(matname);
            else
                matdata = [];
            end
            errflg=0; 
            eval(['[dep,bi,pln,dsym,jclass]=sniff(''' name ...
                                      ''', matdata, tmpname);'], 'errflg=1;');
        else
            errflg = 0;
            eval(['[dep,bi]=examine_fig_file(''' name ...
                                               ''', tmpname);'], 'errflg=1;');
            dsym = {};
            pln = [];
            jclass = {};
        end
       	if errflg
	    % check if file can be opened for reading
	    fid = fopen(name, 'rt');
	    if fid == -1
		prob_files(end+1).name = name;
		prob_files(end).listindex = fc;
		prob_files(end).errmsg = 'Problem opening file';
            else
                fclose(fid);
		prob_files(end+1).name = name;
		prob_files(end).listindex = fc;
		prob_files(end).errmsg = 'Problem compiling file';
            end
            
            % remove problem file from trace and calledfrom lists
            trace_list(fc) = [];
            calledfrom(fc) = [];
            fc = fc - 1;
            
            % Just trying to make sure we never leave this temp m-file.
            if exist(tmpname), delete(tmpname); end
        end

        if ~errflg
    
            % record any evaluated problem strings
            if ~isempty(pln)
                eval_strings(end+1).fcn_name = name;
                eval_strings(end).lineno = pln;
            end
            
            % don't bother to consider dynamic symbols that have been removed
            % from an older version of the problem symbol list
            if ~isempty(dsym)
                ind = logical(zeros(size(dsym)));
                for i=1:length(dsym)
                    if any(strcmp(del_prob_sym,dsym{i}))
                        ind(i) = 1;
                    end
                end
                dsym(ind) = [];
            end
            
            % check if any of the dynamic symbols have methods in the current
            % class list
            if ~isempty(dsym)
                ind = logical(zeros(size(dsym)));
                for i=1:length(dsym)
                    fp = which_with_class(dsym{i},name, clas);
                    if ~isempty(fp)  &  ~any(strcmp(fp,'built-in'))
                        ind(i) = 1;
                        dep{end+1} = fp;
                    end
                end
                dsym(ind) = [];
            end
            
            % save any dynamic symobls in the problem symbol list
            if ~isempty(dsym)
                % remove any duplicate dynamic symbols
                if ~isempty(prob_symbols)
                    ind = logical(zeros(size(dsym)));
                    for i=1:length(dsym)
                        index = find(strcmp({prob_symbols.name},dsym{i}));
                        if ~isempty(index), 
                            ind(i)=logical(1); 
                            prob_symbols(index).fcn_id(end+1) = fc;
                        end
                    end
                    dsym(ind) = [];
                end
                
                if ~isempty(dsym)
                    for i=1:length(dsym)
                        prob_symbols(end+1).fcn_id = fc;
                        prob_symbols(end).name = dsym{i};
                    end
                    for i=1:length(dsym)
                        which_psym{end+1} = whichall(dsym{i});
                    end
                end
            end
            
            % accumulate any new java classes and their methods
            if ~isempty(jclass)
                for i=1:length(jclass)
                    if ~any(strcmp(jclass{i},java_classes))
                        java_classes(end+1) = jclass(i);
                    end
                end
            end

	    % determine if any of the new functions are constructors
	    const = {};
	    nclas = length(clas);
	    if nclas == 0  &  ~toponly
		% initialize inuse classes to include the following:
		clas = {'double' 'char' 'cell' 'struct'};
	    end
	    for i=1:length(dep)
		if any(strcmp(cls,dep{i}))
		    % build list of constructors called in function
                    const(end+1) = dep(i); 
		    % build list of constructors called in all functions
		    if ~any(strcmp(clas,dep{i})), clas(end+1) = dep(i); end
		end
	    end

	    % remove duplicate names in new builtin list
	    if length(builtins)
		ind = zeros(size(bi));
		for i=1:length(bi)
		    if any(strcmp(builtins,bi{i}))
			ind(i) = 1;
		    end
		end
		bi(logical(ind)) = [];
            end
            
            % check for constructors among builtin functions
            for i=1:length(bi)
                if any(strcmp(cls,bi{i}))
                    const(end+1) = bi(i);
                    if ~any(strcmp(clas,bi{i})), clas(end+1) = bi(i); end
                end
            end
            
	    % find full path names for dependent files
	    deps = {};
            for i=1:length(dep)
                % find full path name in context of caller (should get private)
                fp = which_with_class(dep{i},name, clas);
                if isempty(fp)  |  any(strcmp(fp,'variable'))
                    % before including a new symbol in problem symbol list be
                    % sure it hasn't already been in the list and then removed
                    if ~any(strcmp(del_prob_sym,dep{i}))
                        if isempty(prob_symbols)
                            ind = [];
                        else
                            ind = find(strcmp({prob_symbols.name},dep{i}));
                        end
                        if isempty(ind)
                            prob_symbols(end+1).name = dep{i};
                            prob_symbols(end).fcn_id = fc;
                            which_psym{end+1} = whichall(dep{i});
                        else
                            prob_symbols(ind).fcn_id(end+1) = fc;
                        end
                    end
                else
                    deps{end+1} = fp;
                end
	    end

	    % remove duplicate names in new dependency list
	    inc = zeros(size(deps));
	    for i=1:length(deps)
		ind = strcmp(trace_list,deps{i});
		if any(ind)
		    for j=find(ind)
			calledfrom{j}(end+1) = fc;
		    end
		    inc(i) = 0;
		else
		    inc(i) = 1;
		end
	    end
	    deps(~inc) = [];
            
            % check if any of the methods for the problem symbols are to be
            % included because their class is new (only adding first as rest
            % handled below)
            if nclas < length(clas)
                newcls = nclas+1:length(clas);
                ind = logical(zeros(size(prob_symbols)));
                for k=1:length(prob_symbols)
                    if length(which_psym{k})
                        breakout = 0;
                        for j=newcls
                            for l=1:length(which_psym{k})
                                m = findstr(which_psym{k}{l},...
                                    ['@' clas{j} fsep]);
                                if length(m)
                                    deps{end+1} = which_psym{k}{l};
                                    ind(k) = 1;
                                    breakout = 1;
                                    break;
                                end
                            end
                            if breakout, break, end
                        end
                    end
                end
                if any(ind)
                    % need to remove dynamic symbol because it's been added to
                    % the trace list
                    if any(strcmp({prob_symbols(ind).name},'issiso')),keyboard,end
                    del_prob_sym = [del_prob_sym {prob_symbols(ind).name}];
                    prob_symbols(ind) = [];
                    which_psym(ind) = [];
                end
            end

	    % find methods for new classes that correspond to current
	    % trace list
	    ndeps = length(deps);
	    if nclas < length(clas)
		newcls = nclas+1:length(clas);
		for k=1:length(trace_list)
		    % check if there's any methods
		    if length(which_trace_list{k})
			% check if any of the new classes have a method
			ind = zeros(size(which_trace_list{k}));
			for j=newcls
			    for l=1:length(which_trace_list{k})
				m = findstr(which_trace_list{k}{l},...
							['@' clas{j} fsep]);
				if length(m)
				    deps{end+1} = which_trace_list{k}{l};
				    ind(l) = 1;
				end
			    end
			end
			% Once a method has been added to dependency list
			% remove it from which list
			which_trace_list{k}(logical(ind)) = [];
		    end
		end
            end
            
	    % find methods for new trace list files
	    which_deps = {};
	    if ndeps, which_deps{ndeps} = []; end
	    for k=1:ndeps
		% first get nethod list for new trace files
		[path,fname,extension] = fileparts(deps{k});
                if ispc, extension = lower(extension); end
		meth = whichall(fname);
		% eliminate current name from list
		if length(meth)
                    meth = meth(~strcmp(meth,deps{k}));
		    which_deps{k} = meth;
		    for j=1:length(clas)
			ind = zeros(size(meth));
			for l=1:length(meth)
			    m = findstr(meth{l},['@' clas{j} fsep]);
			    if length(m)
				deps{end+1} = meth{l};
				ind(l) = 1;
			    end
			end
		    end
		    which_deps{k}(logical(ind)) = [];
		end
	    end

	    if ndeps < length(deps)
		% added some methods so extend which_deps array
		which_deps{length(deps)} = [];
	    end

	    % add any new which trace list items
	    if length(which_deps)
		which_trace_list = [which_trace_list which_deps];
	    end

	    % add new files to list
	    if ~isempty(deps)
		n = length(trace_list);
		trace_list = [trace_list deps];
		calledfrom(n+1:length(trace_list)) = {fc};
	    end
            
            % add loadobj or saveobj if load or save functions used
            if any(strcmp(bi,'load')), bi{end+1} = 'loadobj'; end
            if any(strcmp(bi,'save')), bi{end+1} = 'saveobj'; end

	    % find methods for builtins corresponding to newly added classes
	    ntl = length(trace_list);
	    if nclas < length(clas)
		newcls = nclas+1:length(clas);
		for k=1:length(builtins)
		    % check if there's any methods
		    if length(which_builtins{k})
			% check if any of the new classes have a method
			ind = zeros(size(which_builtins{k}));
			for j=newcls
			    for l=1:length(which_builtins{k})
				m = findstr(which_builtins{k}{l},...
							['@' clas{j} fsep]);
				if length(m)
				    trace_list{end+1} = which_builtins{k}{l};
				    ind(l) = 1;
				end
			    end
			end
			% clear this method from which list so we
			% don't have to examine is any more
			which_builtins{k}(logical(ind)) = [];
		    end
		end
		if length(trace_list) ~= length(which_trace_list)
		    which_trace_list{length(trace_list)} = [];
		end
	    end

	    % get methods for new found builtin functions
	    which_bi = {};
	    for i=1:length(bi)
		% first need to do which for new builtins
		meth = whichall(bi{i});
		% eliminate anything that's not a method
		ind = zeros(size(meth));
		for k=1:length(meth)
		    if any(meth{k}=='@')
			ind(k) = 1;
		    end
		end
		meth(~ind) = [];

		if length(meth)
		    for k=1:length(clas)
			for j=1:length(meth)
			    if any(findstr(meth{j},['@' clas{k} fsep]))
				trace_list{end+1} = meth{j};
				meth{j} = [];
			    end
			end
		    end
		end

		which_bi{i} = meth;
	    end

	    % set calledfrom for newly added methods
	    if ntl < length(trace_list)
		calledfrom(ntl+1:length(trace_list)) = {fc};
		which_trace_list{length(trace_list)} = [];
	    end

	    which_builtins = [which_builtins which_bi];

	    builtins = [builtins bi];
	end
    end
    if toponly, break; end
end

% clear global variables
gethginfo('clear');

% transpose arrays for easier display
trace_list = trace_list';
builtins = builtins';
prob_files = prob_files';
class_names = clas';
calledfrom = calledfrom';
prob_symbols = prob_symbols';
eval_strings = eval_strings';
java_classes = java_classes';

% Be sure to clean up temp m-file
if exist(tmpname), delete(tmpname); end

if nargout<4 & ~isempty(prob_files)
  fprintf('\nThese files could not be parsed:\n')
  for i=1:length(prob_files)
    disp(['   ' prob_files(i).name])
  end
  fprintf(['Possible problems are files not on the path or files that have syntax errors.\n']); 
end
if nargout<5 & ~isempty(prob_symbols)
  fprintf('\nThese symbols could not be resolved as variables or functions:\n');
  for i=1:length(prob_symbols)
    disp(['   ' prob_symbols(i).name])
  end
  fprintf( ...
['\nIf any of the symbols are function names, you will need to include\n',...
 'those functions in your list of dependent files.\n']);
end
if nargout<6 & ~isempty(eval_strings)
    fprintf(['\nThe following lines call eval, evalin, feval, or have HG callback' ...
			' strings\nand possibly contain functions that are not in the final list:\n']);
    for i=1:length(eval_strings)
        lineno = eval_strings(i).lineno;
        fcn_name = eval_strings(i).fcn_name;
        fprintf('\nFile %s\n', fcn_name);
        switch exist(fcn_name)
        case 2
        	for j=1:length(lineno)
            	str = evalc('dbtype(fcn_name, num2str(lineno(j)))');
            	disp(str(2:end-2)) % Remove extra \n's
        	end
        case 6
        	fprintf('%d  ',lineno);  fprintf('\n');
        end
    end
  fprintf( ...
['\nIf any of the strings contain or evaluate to function names that\n'...
 'were missed, you will need to include those functions in your list\n'...
 'of dependent files.\n']);
end
if nargout < 7  &  ~isempty(java_classes)
    fprintf('\n\nThe following are java classes used by these files:\n');
    for i=1:length(java_classes)
        fprintf('%s\n', java_classes{i});
    end
end

if added_temp
  rmpath(tempdir)
end


% If no outputs are expected uninitialize all outputs to prevent ans displays
if nargout < 1, clear, end

%--------------------------------------------------------------------------
function meth = whichall(fcn_name)
% WHICHALL does which -all command without returning M and P versions of
%          same file.
ispc = strncmp(computer,'PC',2);
meth = which(fcn_name,'-all');
if length(meth) > 1
    % eliminate m-files if corresponding p-file exists
    ind = zeros(size(meth));
    for j=1:length(meth)
        if meth{j}(end) == 'p' | (ispc & (meth{j}(end) == 'P'))
            for l=j+1:length(meth)
                if ispc
                   foundmatch = strcmpi(meth{j}(1:end-1),meth{l}(1:end-1));
                else
                   foundmatch = strcmp(meth{j}(1:end-1),meth{l}(1:end-1));
                end
                if foundmatch
                    ind(l) = 1;
                    break;
                end
            end
        end
    end
    meth(logical(ind)) = [];
end


%--------------------------------------------------------------------------

function w = which_with_class(fname, context, classes)
%WHICH_WITH_CLASS Find file in context or first possible method
w = which(fname, context);

if ~isempty(w)
    % make sure you have something other than java class name
end

if isempty(w)
    % look for method version of function from currently known classes
    meth = whichall(fname);
    w = {};
    fsep = filesep;
    for j=1:length(meth)
        for i=1:length(classes)
            if findstr(meth{j},[fsep '@' classes{i} fsep])
                w = meth{j};
                break;
            end
        end
    end
end

%-------------------------------------------------------------------------------
function [ext_names, int_names, problem_lines, dyn_syms, java_classes] = ...
                                             sniff(fcn_name, matdata, tmpname)
%SNIFF	Examine M/P-file for called functions.
%    EXT_NAMES = SNIFF(FCN_NAME, MATDATA) returns a cell array with the
%    names of mex/p/m-file functions called in FCN_NAME.
%
%    The MATDATA argument is a structure holding MAT-file data from a helper
%    data file used in GUI's and saved HG frames.
%
global cbparam hg_param hg_val cbdef

if isempty(matdata)
    HGVariables = {};
    HGVariableStrings = {};
else
    HGVariables = fieldnames(matdata);
    HGVariableStrings = struct2cell(matdata);
end

% check out pcode looking for function calls
[names, dyn_syms, problem_lines, java_classes, java_imports, java_maybe_classes] = ...
    functionscalled(fcn_name, tmpname, cbparam, HGVariables, HGVariableStrings);

if exist(tmpname), delete(tmpname); end

% check if there is an import list and if so look for java classes in the 
% dynamic symbol list
if ~isempty(java_imports)  |  ~isempty(java_classes)
	[java_classes, names, dyn_syms] = checkout_imports(java_imports, ...
                                               java_classes, names, dyn_syms);
end

% eliminate built-in functions from list
ext_ind = logical(zeros(size(names)));
for i=1:length(names)
    if ~exist(names{i},'builtin')
	ext_ind(i) = 1;
end
end
ext_names = names(ext_ind);
int_names = names(~ext_ind);

%-------------------------------------------------------------------------------
function [java_classes, names, dyn_syms] = checkout_imports(java_imports, ...
                                            java_classes, names, dyn_syms);
% Examine the import list to determine which java classes are being called
% and which dynamic symbols to remove from the list.

for i=1:length(java_imports)
    if java_imports{i}(end) == '*'
        % look thru the dynamic symbols for java classes that belong with this
        % import argument
        ind = logical(zeros(size(dyn_syms)));
        for j=1:length(dyn_syms)
            test_class_name = [java_imports{i}(1:end-1) dyn_syms{j}];
            if exist(test_class_name)
                if ~any(strcmp(java_classes,test_class_name))
                    java_classes{end+1} = test_class_name;
                end
                ind(j) = 1;
            end
        end
        dyn_syms(ind) = [];
                
        % look thru the function symbols for java classes that belong with this
        % import argument
        ind = logical(zeros(size(names)));
        for j=1:length(names)
            test_class_name = [java_imports{i}(1:end-1) names{j}];
            if exist(test_class_name)
                if ~any(strcmp(java_classes,test_class_name))
                    java_classes{end+1} = test_class_name;
                end
                ind(j) = 1;
            end
        end
        names(ind) = [];

    else
        % look thru dynamic symbol list for possible class name
        ind = logical(zeros(size(dyn_syms)));
        for j=1:length(dyn_syms)
            test_class_name = [java_imports{i} '.'  dyn_syms{j}];
            if ~isempty(methods(test_class_name))
                if ~any(strcmp(java_classes,test_class_name))
                    java_classes{end+1} = test_class_name;
                end
                ind(j) = 1;
            end
        end
        dyn_syms(ind) = [];
                
        % look thru dynamic symbol list for possible class name
        ind = logical(zeros(size(names)));
        for j=1:length(names)
            test_class_name = [java_imports{i} '.'  names{j}];
            if ~isempty(methods(test_class_name))
                if ~any(strcmp(java_classes,test_class_name))
                    java_classes{end+1} = test_class_name;
                end
                ind(j) = 1;
            end
        end
        names(ind) = [];

    end
end

% remove dynamic symbols that are methods of any java class or 
% are the leading part of a java class name already found
for i=1:length(java_classes)
    if isempty(dyn_syms), break, end
	ind = logical(zeros(size(dyn_syms)));
    jmeth = methods(java_classes{i});
    for j=1:length(dyn_syms)
        if any(strcmp(jmeth,dyn_syms{j}))
            ind(j) = 1;
        else
        	leadpart = [dyn_syms{j} '.'];
        	len = length(leadpart);
        	if strncmp(leadpart,java_classes{i},len)
            	ind(j) = 1;
            end
        end
    end
	dyn_syms(ind) = [];
end

% remove function names that are the leading names of any java class
ind = logical(zeros(size(names)));
for i=1:length(names)
    dotname = [names{i} '.'];
    namelen = length(dotname);
    for j=1:length(java_classes)
        if any(strncmp(java_classes{j},dotname,namelen))
            ind(i) = 1;
            break
        end
    end
end
names(ind) = [];

% remove function names that are methods of any java class
ind = logical(zeros(size(names)));
for i=1:length(java_classes)
    jmeth = methods(java_classes{i});
    for j=1:length(names)
        if any(strcmp(jmeth,names{j}))
            ind(j) = 1;
        end
    end
end
names(ind) = [];

%-------------------------------------------------------------------------------

function [prop, values, cb, defcbstr] = gethginfo(flg)
%GETHGINFO    Return HG properties, values, and callback names

global cbparam hg_param hg_val cbdef

% clear global variables
if nargin > 0, 
    if strcmp(flg,'clear')
    	clear global cbparam hg_param hg_val cbdef
    elseif strcmp(flg,'setup')
        hg_param = {};
        hg_val   = {};
        cbparam  = {};
        cbdef    = {};
        prop     = hg_param;
    	values   = hg_val;
    	cb       = cbparam;
    	defcbstr = cbdef;
    end
    return
end

if ~isempty(cbparam)
    prop     = hg_param;
    values   = hg_val;
    cb       = cbparam;
    defcbstr = cbdef;
    return;
end

fprintf(1,'\nBuilding list of Handle Graphics callback parameters.\n');

% start with factory default list default
def = fieldnames(get(0,'factory'));

% derive a list of HG classes (start with known object)
hgcls = {'root'};
for i=1:length(def)
    ind = find(def{i} >= 'A'  &  def{i} <= 'Z');
    constr = lower(def{i}(ind(1):(ind(2)-1)));
    if ~strcmp(hgcls,constr)
        hgcls{end+1} = constr;
    end
end

% built complete list of properties
prop = def;  values = {};
for i=1:length(hgcls)
    % create HG object
    if i == 1, obj = 0; else, obj = feval(hgcls{i}); end
    fprintf('.');
    %disp(['working on HG object ' hgcls{i}])

    % get and set property lists
    pg = fieldnames(get(obj));
    ps = fieldnames(set(obj));

    % get value list for set properties
    for j=1:length(ps)
		v = set(obj,ps{j});
		ind = ones(size(v));
		for k=1:length(v)
	    	if any(strcmp(v{k},values)), ind = 0; end
		end
		values = [values; v(logical(ind))];
    end

    if i > 1, delete(obj); end

    % remove duplicate get and set properties
    ind = ones(size(ps));
    for j=1:length(ps)
		if any(strcmp(pg,ps{j})), ind(j) = 0; end
    end
    p = [pg; ps(logical(ind))];

    % remove duplicate properties
    ind = ones(size(p));
    for j=1:length(p)
		if any(strcmp(p{j},prop)), ind(j) = 0; end
    end
    prop = [prop; p(logical(ind))];
end
fprintf('  done\n');

% look thru list of properties and extract callbacks
cb = {'callback'};
for i=1:length(prop)
    if strcmp(prop{i}(end-2:end),'Fcn'), cb{end+1} = lower(prop{i}); end
end
for i=1:length(prop)
    if length(prop{i}) > 8  &  strcmp(prop{i}(end-7:end),'Callback')
	cb{end+1} = lower(prop{i});
    end
end
cb = cb';

% get default string for callbacks
defcbstr = {};
for i=1:length(cb)
    cls = 0;
    for j=1:length(hgcls)
		if ~isempty(findstr(cb{i},hgcls{j})), cls=j; break; end
    end
    if cls & ~strcmp('root',hgcls{cls}) & ...
            			(strncmp('factory',cb{i},7) | strncmp('default',cb{i},7))
		defstr = get(0,cb{i});
		if ~isempty(defstr), defcbstr{end+1} = defstr; end
    end
end

close all

%lower case all HG data
for i=1:length(prop),     prop{i}     = lower(prop{i}); end
for i=1:length(values),   values{i}   = lower(values{i});   end
for i=1:length(cb),       cb{i}       = lower(cb{i});  end
for i=1:length(defcbstr), defcbstr{i} = lower(defcbstr{i});    end

% save HG data to global variables
hg_param = prop;
hg_val  = values;
cbparam = cb;
cbdef   = defcbstr;

%-------------------------------------------------------------------------------

function [class_list] = classes
%CLASSES    Return cell array with all external class types.

% get matlab path string
dirs = [cd pathsep matlabpath];

% make subscript array that brackets path components
ind = [0 find(dirs == pathsep) length(dirs)+1];

class_list = {};

% walk matlab path
for i=1:length(ind)-1
    % get next path
    path = dirs(ind(i)+1:ind(i+1)-1);

    % do a dir on directory listing all @ directories
    if path(end) == filesep
	atdirs = dir([path '@*']);
    else
	atdirs = dir([path filesep '@*']);
    end

    % remove duplicate classes from above list
    flg = zeros(size(atdirs));
    for i=1:length(atdirs)
	if any(strcmp(class_list,atdirs(i).name)), 
	    flg(i) = 0; 
	else 
	    flg(i) = 1; 
	end
    end

    % add classes to list
    if ~isempty(flg)  &  any(flg)
	class_list = [class_list {atdirs(logical(flg)).name}];
    end
end

% remove @ symbol from each list name
for i=1:length(class_list)
    class_list{i} = class_list{i}(2:end);
end

%-------------------------------------------------------------------------------

function cbstrings = findfigcb(figstruct, cbnames)
% find callback strings in figure structure

cbstrings = {};

structnames  = fieldnames(figstruct);
lstructnames = lower(structnames);
nfield = length(structnames);

% run thru all elements of input structure array
for i=1:length(figstruct)
    % run thru each field of structure
    for j=1:nfield
        fi = getfield(figstruct(i), structnames{j});
        if any(strcmp(cbnames,lstructnames{j}))
            if ischar(fi)
                cbstrings{end+1} = fi;
            else
                disp('Callback string expected but not gotten'), keyboard
            end
        elseif isstruct(fi)
            cbstrings = [cbstrings findfigcb(fi,cbnames)];
        end
    end
end
%-------------------------------------------------------------------------------


function [list] = parse_string(str, tmpname)
% Parse string and return parse tree for string.
%

%If empty string returnempty tree
if isempty(str), list={}; return, end

% create temporary file that is input script with function header
fidtmp = fopen(tmpname, 'wt');
if fidtmp == -1, error(['Unable to open file ' tmpname]), end

fprintf(fidtmp, ['function varargout = dummy(varargin)\n']);
fwrite(fidtmp, str, 'char');

fclose(fidtmp);

% need another temp file
tmpname1 = [tempname '.m'];

% generate parse tree structure
evalstr = ['list = functionscalled(''' tmpname ''', ''' tmpname1 ''');'];
errflg = 0; eval(evalstr, 'errflg = 1;');

delete(tmpname);
delete(tmpname1);

if errflg, 
    list = {};     % need to return something 
end


%-------------------------------------------------------------------------------


function [ext_names, int_names] = examine_callback_str(str, tmpname)
% Examine callback strings for external, builtin functions and
% eval strings.
%

names = parse_string(str, tmpname);

% eliminate built-in functions from list
ext_ind = logical(zeros(size(names)));
for i=1:length(names)
    if ~exist(names{i},'builtin')
	ext_ind(i) = 1;
    end
end
ext_names = names(ext_ind);
int_names = names(~ext_ind);




%-------------------------------------------------------------------------------


function newlist = addnondup2list(oldlist, additions)
% Add non-duplicate names to old list.

if length(oldlist) == 0,  newlist = additions;, return, end
if length(additions) == 0, newlist = oldlist; return, end

ind = logical(zeros(size(additions)));
for i=1:length(additions)
    if any(strcmp(oldlist, additions{i}))
        ind(i) = 1;
    end
end

newlist = [oldlist additions(~ind)];

%-------------------------------------------------------------------------------

function [ext_names, int_names] = examine_fig_file(fname, tmpname)
% Examine HG structure in FIG file and return list of external and
% builtin functions and eval strings
%

ext_names = {};  int_names = {};

% get handle graphics info
[hg_param, hg_val, cbparam, cbdef] = gethginfo;

% get HG figure structure
data = load('-mat', fname);
fn = fieldnames(data);
if length(fn) > 1, error('Figure file has more than one item'), end
hg_struct = getfield(data, fn{1});

% locate callback strings withing HG structure
cbstrings = findfigcb(hg_struct, cbparam);

% run thru list of callback strings
for i=1:length(cbstrings)
    [extnames, binames] = examine_callback_str(cbstrings{i}, tmpname);
    
    % add non-duplicate names to lists
    ext_names = addnondup2list(ext_names, extnames);
    int_names = addnondup2list(int_names, binames);
end
