function FSplit(varargin)
% FSPLIT splits a multifunction m-file into many single function m-files
%
% FSPLIT(SOURCEFILE) reads the multifunction m-file SOURCEFILE and writes a
% new m-file for each function in SOURCEFILE into the current directory,
% splitting the SOURCEFILE by functions. If no path is specified for the
% source file, it is read from the current directory or from the Matlab
% path, in that order.
%
% FSPLIT(SOURCEFILE, TARGETDIR) writes the individual functions in
% SOURCEFILE into the directory TARGETDIR.
%
%
% Example:
%
% >> FSplit('ver.m','.\test')
% FSplit reading file C:\MATLAB\toolbox\matlab\general\ver.m
%
% Writing function ver.m ... finished
% Writing function fixarg.m ... finished
% Writing function LocParseContentsFile.m ... finished
% Writing function LocDisplayMatlabInformation.m ... finished
% Writing function sort_toolbox_list.m ... finished
% Writing function display_toolbox_list.m ... finished
% Writing function remove_unwanted_entries.m ... finished
% Writing function disp_single_toolbox.m ... finished
% Writing function LocCleanDate.m ... finished
%
% FSplit finished.
%
%
% Author: Stead Kiger, Ph.D.
% Department of Radiation Oncology
% Beth Israel Deaconess Medical Center
% Harvard Medical School
% Last Modified: December 21, 2006
%
% Copyright (C) 2006 Stead Kiger, Ph.D.
%
% This program is distributed under the terms of the BSD license, available
% at http://www.opensource.org/.
stdIO=1;
% Assign the source file and target directory
sourceFile=varargin{1};
[pathStr,fileName,ext,versn] = fileparts(sourceFile);
if nargin==1,
targetDir=pwd;
elseif nargin==2,
targetDir=varargin{2};
else
error('Wrong number of arguments');
end
% If no path was specfied for the source file, check that the source file
% exists in the current directory. If not, use which(sourceFile) to
% determine whether it exists somewhere in the Matlab path.
if isempty(pathStr),
if ~exist(fullfile(pwd,sourceFile),'file'),
% look for the m-file in the Matlab path using which
foundFile=which(sourceFile);
if isempty(foundFile),
error('The source file %s could not be found.');
else
sourceFile=foundFile;
end
end
end
% Check that the target directory exists and if not, create it
if exist(targetDir,'dir')==7,
% the target directory exists
else
% try to create the target directory
[success,msg,msgID] = mkdir(targetDir);
if ~success,
display(msg)
error('Could not create target directory %s.',targetDir)
end
end
% Open the source file for reading
outFID=-1;
srcFID=fopen(sourceFile,'rt');
if srcFID==-1,
error('The source file %s could not be opened.',sourceFile)
else
outFileIsOpen=false;
fprintf(stdIO,'%s reading file %s\n\n',mfilename, sourceFile)
% Read the source file until its end is reached
while ~feof(srcFID),
lineStr=fgetl(srcFID);
% Look for occurences of 'function', which of course denotes a new
% function
if ~isempty(regexpi(lineStr, 'function ', 'start')),
% check for line continuation (...)
contIdx=regexpi(lineStr, '\.\.\.', 'start');
if ~isempty(contIdx),
srcFilePos=ftell(srcFID); % position before more reads
syntaxDef=[];
contLineStr=lineStr;
% read until there are no more line continuations, building
% up the syntax definition line so that we can determine
% the function name
while ~isempty(contIdx),
syntaxDef=[syntaxDef contLineStr(1:contIdx-1)];
contLineStr=fgetl(srcFID);
contIdx=regexpi(contLineStr, '\.\.\.', 'start');
end
syntaxDef=[syntaxDef contLineStr]; % add final line
[newFunName]=GetFunctionName(syntaxDef);
% reset the file position to just after we read the first
% continuation line
status=fseek(srcFID, srcFilePos, 'bof');
else
[newFunName]=GetFunctionName(lineStr);
end
if ~isempty(newFunName),
% Close the current m-file
if outFileIsOpen,
fclose(outFID);
fprintf(stdIO,'finished\n')
end
% Open a new m-file for the new function
outFileSpec=fullfile(targetDir,[newFunName '.m']);
if exist(outFileSpec,'file'),
error('Output file %s already exists',outFileSpec)
else
outFID=fopen(outFileSpec,'wt');
outFileIsOpen=true;
count=fprintf(outFID,'%s\n',lineStr);
fprintf(stdIO,'Writing function %s ... ',[newFunName '.m'])
end
end
else
if outFileIsOpen,
count=fprintf(outFID,'%s\n',lineStr);
end
end
end
fprintf(stdIO,'finished\n') % finished writing the last function
if outFID~=-1,
fclose(outFID);
end
fprintf(stdIO,'\n%s finished.\n\n',mfilename)
end
end
function [newFunName]=GetFunctionName(lineStr)
% GETNEWFUNCTIONNAME extracts the function name from a syntax definition line
%
% [newFunName]=GetFunctionName(lineStr) analyzes a possible syntax
% definition line to find a function name. It ignores commented syntax
% definition lines, i.e., behind a % sign. If no function name is found,
% newFunName is returned empty.
%
% The possibilities for syntax definition lines are:
%
% function foo
% function a = foo
% function [a,b,c, ...] = foo
% function [a,b,c, ...] = foo(x,y,z, ...)
% first check that it is not actually a comment
fcnIdx=strfind(lower(lineStr),'function ');
pctIdx=strfind(lineStr,'%');
if ~isempty(pctIdx),
if pctIdx < fcnIdx,
newFunName=[];
return
end
% Delete the comment
lineStr=lineStr(1:pctIdx-1);
end
% Delete the word function
lineStr=lineStr(fcnIdx+9:end);
% look for an equals sign
eqIdx=strfind(lineStr,'=');
if ~isempty(eqIdx),
% Delete all characters to the left of (and including) the equals sign
lineStr=lineStr(eqIdx+1:end);
end
% Look for a left parenthesis
ltParenIdx=strfind(lineStr,'(');
if ~isempty(ltParenIdx),
% Delete all characters to the right of the parenthesis (inclusive)
lineStr=lineStr(1:ltParenIdx-1);
end
% Deblank both sides of what is hopefully the remaining function name
newFunName=strtrim(lineStr);
end