Code covered by the BSD License  

Highlights from
program_statistics

from program_statistics by Laurent Cavin
PROGRAM_STATISTICS compiles some statistics about a program. A report is printed;

program_statistics(direct, varargin)
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

Contact us at files@mathworks.com