function varargout = program_statistics(direct, varargin) % PROGRAM_STATISTICS compiles some statistics about a program. % A report is printed; statistics can be returned in structure. % % program_statistics(direct) % stats = program_statistics(direct); % stats = program_statistics(direct, options); % % direct: directory where the program resides % options: a structure with the following optional fields: % .recursive = 0|1 take also into account subfolders recursively % .complete = 0|1 compile extended set of statistics (see below) % .include cell array of text files types (.xxx) to % include in the statistics (e.g. {'.txt'; '.c'} % % stats contains the following fields: % .files number of m files % .lines number of lines % .words number of words % .chars number of characters % .pages number of pages to print the whole program based on: % A4, landscape layout, default matlab impression % fonts, margins, etc... % "complete statistics" option add the following fields: % .functions number of functions % .space number of space/tab/newline characters % .emptline number of empty lines % .sigchar number of non space/tab/newline characters % .comments number of comments line (beginning with %) % .comchar number of comment characters % .codelines number of lines of code (comment lines are ignored) % .GUIDE number of GUI files made with GUIDE % .GUIDEf number of "GUIDE" functions % .GUIDEb number of bytes of the GUIDE-related .fig files % % note: stats = program_statistics(direct, options, 0) does not print a % report. % % Programmed by CSE - L.Cavin, 2004, version 1.0 % Use freely for any non-comercial purposes. % % EXAMPLE OF REPORT: % % % % Number of folders parsed: 44 % % Number of code folders: 8 (22.125 files per folder) % % % % Number of files: 177 % % - including 588 functions (3.322 functions per file), % % - including 25 GUI dialog callback files made with GUIDE, % % (linked with .fig files weighting 657.3438 Kb) % % - including 335 GUIDE-related functions, % % - including 253 other functions (1.6645 functions per file). % % % % Number of lines: 40600 % % - distributed in 172234 words, % % - including 2774 (6.8325%) separation lines, % % - including 8606 (21.197%) lines of comments, % % - including 29220 (71.9704%) lines of code. % % % % Number of characters: 1549343 % % - including 407452 (26.2984%) comment characters, % % - including 1141891 (73.7016%) code characters. % % % % To print the whole program, 1014 A4-pages would be necessary. cur_dr = pwd; % setup options if nargin > 1 options = varargin{1}; else options = []; end if ~isfield(options, 'recursive') options.recursive = 0; end if ~isfield(options, 'complete') options.complete = 0; end if ~isfield(options, 'include') options.include = []; end % initialize stats stats.files = 0; stats.lines = 0; stats.words = 0; stats.chars = 0; stats.pages = 0; if options.recursive stats.folders = 0; stats.projfold = 0; end if options.complete stats.emptline = 0; stats.functions = 0; stats.GUIDE = 0; stats.GUIDEf = 0; stats.GUIDEb = 0; stats.sigchar = 0; stats.space = 0; stats.comments = 0; stats.comchar = 0; stats.codelines = 0; end cd(direct); % begin with recursivity loop is required: if options.recursive subdir = dir; for i = 1:length(subdir) if subdir(i).isdir & ~prod(double('.' == subdir(i).name)) stats.folders = stats.folders + 1; stats.projfold = stats.projfold + 1; stt = program_statistics([direct filesep subdir(i).name], options, 0); if stt.files == 0 stats.projfold = stats.projfold - 1; end stats = add_stats(stats, stt); end end end fles = dir('*.m'); if ~isempty(options.include) for i = 1:length(options.include) tmp = dir(['*' options.include{i}]); fles = [fles; tmp]; end end stats.files = stats.files + length(fles); cmt = 0; spc = 0; for i = 1:length(fles) pge = 0; fle = textread(fles(i).name, '%s'); stats.words = stats.words + length(fle); fle = textread(fles(i).name,'%s','delimiter','\n','whitespace',''); stats.lines = stats.lines + length(fle); cmt = cmt + length(fle); spc = spc + length(fle); chr = 0; for j = 1:length(fle) tmp = length(fle{j}); stats.chars = stats.chars + tmp; spc = spc + tmp; pge = pge + ceil(tmp/119); chr = chr + tmp; end stats.pages = stats.pages + ceil(pge/42); if options.complete fid = fopen(fles(i).name); tmp = length(fscanf(fid, '%s')); stats.sigchar = stats.sigchar + tmp; spc = spc - tmp; fclose(fid); fle = textread(fles(i).name,'%s','delimiter','\n','whitespace','', 'commentstyle', 'matlab'); stats.codelines = stats.codelines + length(fle); cmt = cmt - length(fle); fcn = 0; gde = 0; for j = 1:length(fle) if length(fle{j}) == 0 stats.emptline = stats.emptline + 1; else if ~isempty(findstr(fle{j}, 'function')) if (fle{j}(1) == 'f') & (fle{j}(2) == 'u') stats.functions = stats.functions + 1; if ~isempty(findstr(fle{j} , '(hObject, eventdata, handles)')) fcn = fcn + 1; end end end chr = chr - length(fle{j}); if ~isempty(findstr(fle{j}, 'gui_Singleton = 1;')) stats.GUIDE = stats.GUIDE + 1; gde = 1; tmp = dir([fles(i).name(1:end-1) 'fig']); if ~isempty(tmp) stats.GUIDEb = stats.GUIDEb + tmp.bytes; end end end end if gde stats.GUIDEf = stats.GUIDEf + fcn + 1; end stats.comchar = stats.comchar + chr; end end if options.complete stats.comments = stats.comments + cmt; stats.space = stats.space + spc; end cd(cur_dr); if nargin < 3 % print report: disp(' '); disp('PROGRAM STATISTICS:'); disp('~~~~~~~~~~~~~~~~~~~'); disp(' '); if options.recursive stats.folders = stats.folders + 1; stats.projfold = stats.projfold + 1; disp(['Number of folders parsed: ' int2str(stats.folders)]); disp(['Number of code folders: ' int2str(stats.projfold) ' (' num2str(stats.files/stats.projfold) ' files per folder)']); disp(' '); end disp(['Number of files: ' int2str(stats.files)]); if options.complete disp([' - including ' int2str(stats.functions) ' functions (' num2str(stats.functions/stats.files) ' functions per file),']); disp([' - including ' int2str(stats.GUIDE) ' GUI dialog callback files made with GUIDE,']); disp([' (linked with .fig files weighting ' num2str(stats.GUIDEb/1024) ' Kb)']); disp([' - including ' int2str(stats.GUIDEf) ' GUIDE-related functions,']); disp([' - including ' int2str(stats.functions-stats.GUIDEf) ' other functions (' num2str((stats.functions-stats.GUIDEf)/(stats.files-stats.GUIDE)) ' functions per file).']); disp(' '); end disp(['Number of lines: ' int2str(stats.lines)]); if options.complete disp([' - distributed in ' int2str(stats.words) ' words,']); disp([' - including ' int2str(stats.emptline) ' (' num2str(stats.emptline/stats.lines*100) '%) separation lines,']); disp([' - including ' int2str(stats.comments) ' (' num2str(stats.comments/stats.lines*100) '%) lines of comments,']); disp([' - including ' int2str(stats.codelines-stats.emptline) ' (' num2str((stats.codelines-stats.emptline)/stats.lines*100) '%) lines of code.']); disp(' '); else disp(['Number of words: ' int2str(stats.words)]); end disp(['Number of characters: ' int2str(stats.chars)]); if options.complete % disp([' - including ' int2str(stats.space) ' (' num2str(stats.space/stats.chars*100) '%) spaces, tabs, newlines,']); % disp([' - including ' int2str(stats.sigchar) ' (' num2str(stats.sigchar/stats.chars*100) '%) other characters,']); % disp([' - including ' int2str(stats.comchar) ' (' num2str(stats.comchar/stats.chars*100) '%) comment characters,']); % disp([' - including ' int2str(stats.sigchar-stats.comchar) ' (' num2str((stats.sigchar-stats.comchar)/stats.chars*100) '%) code characters']); disp([' - including ' int2str(stats.comchar) ' (' num2str(stats.comchar/stats.chars*100) '%) comment characters,']); disp([' - including ' int2str(stats.chars-stats.comchar) ' (' num2str((stats.chars-stats.comchar)/stats.chars*100) '%) code characters.']); end disp(' '); disp(['To print the whole program, ' int2str(stats.pages) ' A4-pages would be necessary.']); disp(' '); end if nargout > 0 varargout{1} = stats; end function stats = add_stats(stats, stt) blp = fields(stats); for i = 1:length(blp) eval(['stats.' blp{i} ' = stats.' blp{i} ' + stt.' blp{i} ';']); end