Code covered by the BSD License  

Highlights from
missingsemicolons

from missingsemicolons by Brett Shoelson
Helps locate output-producing lines of code that are missing semicolons.

missingsemicolons(targetfiles, suppress_subdir_eval)
function linevals = missingsemicolons(targetfiles, suppress_subdir_eval)
% LINEVALS = MISSINGSEMICOLONS(TARGETFILES, SUPPRESS_SUBDIR_EVAL)
% 
% Returns in 'linevals' a structure containing the line numbers and
% offending strings of lines that are likely candidates for missing
% terminal semicolon. Lines commencing with keywords that typically
% do not produce an output at the command line
% (e.g., 'if', 'return', 'continue', etc.) are skipped.
%
% TARGETFILES: Input may be either a string indicating a path to a
% single mfile (e.g., 'aviplayer.m', 'c:\brett\targetfiless\aviplayer.m'),
% a directory of files (eg. dir('*.m')), OR a name/path to the target
% directory. If a directory is input, the program examines all files in
% the directory AND, by default, subdirectories, compiling in a
% single structure the individual output for each file. To suppress
% inclusion of subdirectories, enter 1 for the optional second argument.
%
% SUPPRESS_SUBDIR_EVAL (optional; default = 0): By default, subdirectories
% are included if TARGETFILES is the name of a directory. To suppress this
% behavior, enter a 1 for this argument. (If TARGETFILES is NOT a directory,
% this argument is ignored.)
%
% EXAMPLES:
%          suspects = missingsemicolons('aviplayer.m')
%
%          a=dir('keyword*.m'); suspects = missingsemicolons(a);
%
%          suspects = missingsemicolons('c:\brett\mfiles\afm');
%
% This function uses regular expressions, and thus will not work in
% versions prior to 6.5. In the "credit-where-credit-is-due" category,
% please note that this function calls Peter Acklam's excellent function
% MLSTRIPCOMMENTS, which is available for download from ML Central. I could
% not have written this program without Peter's assistance.
%
% PERFORMANCE NOTE: If you are still getting extraneous output at the
% command line after addressing all instances of forgotten semicolons
% returned by missingsemicolons.m, consider commands "hidden within
% strings." For instance, eval('a=1') will produce output, but will not be
% caught by this program. Similarly, output generated by GUIcallbacks enclosing
% strings will generally not be detected by missingsemicolons.m.
%
% Brett Shoelson, Ph.D.
% shoelson@helix.nih.gov
% 6/25/04

if ~nargin | nargin > 2
    error(sprintf('You must enter one or two arguments. The first may be the name of a single targetfiles,\nor a (structure) containing the a directory of targetfiless,\nor the name of a directory.\nThe second (optional) argument suppresses recursive analysis of subdirectories. (See HELP comments for details.)'));
elseif nargin == 1
	suppress_subdir_eval = 0;
end
if ~isstruct(targetfiles) && strcmp(targetfiles,'mstmpfile.m')
	error('Please do not try to examine this temporary file!');
end
linevals = [];


if isstruct(targetfiles)
	for ii = 1:length(targetfiles)
		fprintf('Examining file %s (%i of %i)....\n',targetfiles(ii).name,ii,length(targetfiles));
		if ~strcmp(targetfiles(ii).name,'mstmpfile.m')
			linevals = examinefile(targetfiles(ii).name,linevals);
		end
	end
elseif isdir(targetfiles)
	if ~suppress_subdir_eval
		paths = genpath(targetfiles);
		%Find instances of the path separator
		seplocs = findstr(paths,pathsep);
		%Parse paths into individual subdirectories
		if ~isempty(seplocs)
			directories = cell(length(seplocs),1);
			directories{1} = paths(1:seplocs(1)-1);
			for ii = 1:length(seplocs)-1
				directories{ii+1} = paths(seplocs(ii)+1:seplocs(ii+1)-1);
			end
		end
	else
		directories = {targetfiles};
	end
	for ii = 1:length(directories)
		tmp = dir([directories{ii},'\*.m']);
		for jj = 1:length(tmp)
			if ~strcmp(tmp(jj).name,'mstmpfile.m')
				fprintf('Examining file %s....\n',tmp(jj).name);
				linevals = examinefile(tmp(jj).name,linevals);
			end
		end
	end
elseif strcmp(class(targetfiles),'char')
	linevals = examinefile(targetfiles,linevals);
else
	error('Inappropriate input argument. Enter a single string or a structure.');
end

function [linevals] = examinefile(fname,linevals)
mlstripcommentsfile(fname,'mstmpfile.m');
fid = fopen('mstmpfile.m', 'r');
if fid == -1
	fprintf('Unable to open/examine file %s. It will be skipped.\n', fname);
	return
end

lnum = 0;
while 1
	lnum = lnum+1;
	if lnum == 1, last3 = [];else,if length(tmpline)>2,last3 = tmpline(end-2:end);else last3 = [];end;end
	if strcmp(last3,'...'),prevline = tmpline(1:end-3);else,prevline = [];end
	tmpline = fgetl(fid);
	if ~ischar(tmpline),break, end
	% Remove leading whitespace:
	tmpline = regexprep(tmpline, '^\s+', '');
	% Remove trailing whitespace:
	tmpline = regexprep(tmpline, '\s+$', '');
	if ~isempty(tmpline)
		space = findstr(' ',tmpline);
		if isempty(space),space = length(tmpline)+1;end
		openparen = findstr('(',tmpline);
		if isempty(openparen),openparen = length(tmpline)+1;end
		openbracket = findstr('[',tmpline);
		if isempty(openbracket),openbracket = length(tmpline)+1;end
		opencurly = findstr('{',tmpline);
		if isempty(opencurly),opencurly = length(tmpline)+1;end
		space = min([min(space),min(openparen),min(openbracket),min(opencurly)]);
		keyword = tmpline(1:space-1);
		if ~isempty(prevline),tmpline = [prevline,tmpline];continue;end
		if length(tmpline)>2,tmp=tmpline(end-2:end);else,tmp=[];end
		if ~strcmp(tmpline(end),';') & ~strcmp(tmp,'...') & ~ismember(keyword,...
				{'if','for','function','disp','while','end','return','global','else','continue','elseif','try','catch',...
					'switch','case','break','continue','otherwise','warning','set','uicontrol','persistent','clear','load',...
					'fprintf','cd','drawnow','beep','pause','error','delete','release','eval',...
					'setappdata','orient','close','otherwise','hold','cla','clc'})
			if isempty(tmpline)
				beep
				pause
			end
			if isempty(linevals)
				linevals = struct('Filename',fname,'LineNumber',lnum,'String',tmpline);
			else
				linevals(length(linevals)+1).Filename = fname;
				linevals(length(linevals)).LineNumber = lnum;
				linevals(length(linevals)).String = tmpline;
			end
		end
	end
end
fclose(fid);
try
	delete('mstmpfile.m');
end
return

Contact us at files@mathworks.com