% Computes percentage of lines that are comments of all the m-files in a folder.
function comment_counter()
clc;    % Clear the command window.
close all;  % Close all figures (except those of imtool.)
clear;  % Erase all existing variables. Or clearvars if you want.
workspace;  % Make sure the workspace panel is showing.
format long g;
format compact;

% Start with a folder and get a list of all subfolders.  Use with R2016b and later.
% It's done differently with R2016a and earlier, with genpath().
% Finds and prints names of all files in that folder and all of its subfolders.
% Similar to imageSet() function in the Computer Vision System Toolbox: http://www.mathworks.com/help/vision/ref/imageset-class.html

% Initialization steps:
clc;    % Clear the command window.
workspace;  % Make sure the workspace panel is showing.
format long g;
format compact;

% Define a starting folder.
start_path = pwd;
if ~exist(start_path, 'dir')
	start_path = matlabroot;
end
% Ask user to confirm the folder, or change it.
uiwait(msgbox('Pick a starting folder on the next window that will come up.'));
topLevelFolder = uigetdir(start_path);
if topLevelFolder == 0
	return;
end
fprintf('The top level folder is "%s".\n', topLevelFolder);

% Specify the file pattern.
% Get ALL files using the pattern *.*
% Note the special file pattern.  It has /**/ in it if you want to get files in subfolders of the top level folder.
% filePattern = sprintf('%s/**/*.m; %s/**/*.xml', topLevelFolder, topLevelFolder);
filePattern = sprintf('%s/**/*.m', topLevelFolder);
allFileInfo = dir(filePattern);

% Throw out any folders.  We want files only, not folders.
isFolder = [allFileInfo.isdir]; % Logical list of what item is a folder or not.
% Now set those folder entries to null, essentially deleting/removing them from the list.
allFileInfo(isFolder) = [];
% Get a cell array of strings.  We don't really use it.  I'm just showing you how to get it in case you want it.
listOfFolderNames = unique({allFileInfo.folder});
numberOfFolders = length(listOfFolderNames);
fprintf('The total number of folders to look in is %d.\n', numberOfFolders);

% Get a cell array of base filename strings.  We don't really use it.  I'm just showing you how to get it in case you want it.
listOfFileNames = {allFileInfo.name};
totalNumberOfFiles = length(listOfFileNames);
fprintf('The total number of files in those %d folders is %d.\n', numberOfFolders, totalNumberOfFiles);

allCommentLines = 0;
allTotalLines = 0;
minAllowablePercentage = 0.25

% Process all files in those folders.
totalNumberOfFiles = length(allFileInfo);
% Now we have a list of all files, matching the pattern, in the top level folder and its subfolders.
if totalNumberOfFiles >= 1
	for k = 1 : totalNumberOfFiles
		% Go through all those files.
		thisFolder = allFileInfo(k).folder;
		thisBaseFileName = allFileInfo(k).name;
		fullFileName = fullfile(thisFolder, thisBaseFileName);
% 		fprintf('     Processing file %d of %d : "%s".\n', k, totalNumberOfFiles, fullFileName);

		[~, baseNameNoExt, ~] = fileparts(thisBaseFileName);
% 		fprintf('%s\n', baseNameNoExt);
		[commentLines, totalLines, percentage] = ProcessOneFile(fullFileName);
		allCommentLines = allCommentLines + commentLines;
		allTotalLines = allTotalLines + totalLines;
		if percentage < minAllowablePercentage
			message = sprintf('File %s has less than the recommended number of comment lines (%d instead of %d)', thisBaseFileName, commentLines, ceil(totalLines * minAllowablePercentage));
			uiwait(warndlg(message));
		end
	end
else
	fprintf('     Folder %s has no files in it.\n', thisFolder);
end
fprintf('\nDone looking in all %d folders!\nFound %d files in the %d folders.\n', numberOfFolders, totalNumberOfFiles, numberOfFolders);
fprintf('Overall, in %d lines, %d lines (%.2f %%) had comments.\n', allTotalLines, allCommentLines, allCommentLines/allTotalLines*100);
fprintf('Over the %d files, the average number of lines was %.1f, and the average number of comment lines was %.1f.\n', totalNumberOfFiles, allTotalLines/totalNumberOfFiles, allCommentLines/totalNumberOfFiles);


function [commentLines, totalLines, percentage] = ProcessOneFile(fullFileName)
% Open the file.
fileID = fopen(fullFileName);
% Read the first line of the file.
textLine = fgetl(fileID);
lineCounter = 1;
commentCounter = 0;
while ischar(textLine)
	% Read the remaining lines of the file.
% 	fprintf('Line %4d: %s\n', lineCounter, textLine);
	textLine = strtrim(textLine);
	lineCounter = lineCounter + 1;
	if ~isempty(textLine)
		textLine2 = textLine;
		% Find where the quotes are so we can see if the % is part of a format specifier string in sprintf() or fprintf() or some other string.
		quoteLocations = strfind(textLine, '''');
		if length(quoteLocations) > 2
			for k = 1 : 2 : length(quoteLocations)-1
				% Erase code between quotes.
				textLine2(quoteLocations(k):quoteLocations(k+1)) = ' ';
			end
		end
		
		percentLocations = strfind(textLine, '%');
		if ~isempty(percentLocations)
			% There's a % in there somewhere.
			if length(percentLocations) == 1
				% Only one % on a line so it's most likely a comment.
				commentCounter = commentCounter + 1;
			elseif length(percentLocations) >= 2
				if isempty(strfind(textLine, 'sprintf')) && isempty(strfind(textLine, 'fprintf'))
					% Only count this line if there is no sprintf() or fprintf() on the line.
					commentCounter = commentCounter + 1;
				else
					% Not a line with a comment.
					;
				end
			end
		end
	end
	
	% Read the next line.
	textLine = fgetl(fileID);
	if textLine == -1
		continue;
	end
end
% All done reading all lines, so close the file.
fclose(fileID);
percentage = 100 * commentCounter / lineCounter;
commentLines = commentCounter;
totalLines = lineCounter;
[~, baseFileName, ext] = fileparts(fullFileName);
fprintf('In file %s, found %d lines total.  Of those, %d, or %.2f%% were comment lines.\n', ...
	baseFileName, lineCounter, commentCounter, percentage);
