No BSD License  

Highlights from
CatOrSplitFile

image thumbnail
from CatOrSplitFile by Michael Robbins
concatenates or splits files with an optional token header.

CatOrSplitFiles(varargin)
function out = CatOrSplitFiles(varargin)
% CATORSPLITFILES concatenates or splits files with an optional token
% header.
%
% CATORSPLITFILES('CAT',FILENAME,TARGETFILENAME,param,value, ...)
% FILENAMES = CATORSPLITFILES('SPLIT',TARGETFILENAME,param,value, ...)
%
% CAT (concatenate) PARAMETERS, VALUES AND DEFAULTS
%    Parameter       Values         Defaults
%    ---------  ----------------    --------
%    HEADER     'OFF','%','NO%'     '%'
%    SILENT     'OFF','ON'          'OFF'
%    PROP       'OFF','ON'          'OFF'
%
% If HEADER is % (default) each file that is combined will be titled with a
% comment that begins with % and is easily recognisible.  If you should
% desire to split the file up again, CATORSPLITFILES can use this comment
% to do it properly.
%
% If HEADER is NO%, the action is very similar to the default action except
% the comment does not begin with %.
%
% If HEADER is OFF, then all the files are combined into one large one.  If
% this is done it may not be reversible since the only way to split them
% again is with the FUN feature.
%
% If SILENT is ON, the CATORSPLITFILE will not prompt the user before
% overwriting a file.
%
% The PROP feature is proprietary and not available to the public.
% 
% which may not split the file where it was originally since it will split
% on the function definitions.  If one of the original files had more than
% one function definition or if one of the original files 
%
% SPLIT PARAMETERS, VALUES AND DEFAULTS
%    Parameter       Values         Defaults
%    ---------  ----------------    --------
%    HEADER     '%','NO%','FUN'     '%'
%    SILENT     'OFF','ON'          'OFF'
%    BACKUP     'OFF','ON'          'ON'
%    SPLITTO    string              where it came from
%
% If HEADER is % (default) the file will be split on a comment produced
% with CATORSPLITFILES that begins with % and is easily recognisible.
%
% If HEADER is NO%, the action is very similar to the default action except
% the comment does not begin with %.
%
% If HEADER is FUN, then CATORSPLITFILE will split on function definitions
% putting each function in a different m-file.
%
% If SILENT is ON, the CATORSPLITFILE will not prompt the user before
% overwriting a file.
%
% If BACKUP is ON (default), CATORSPLITFILE will not backup files before
% overwriting them.  The backed up file will have the same name, but will
% have the .bak extension.
%
% If SPLITTO is not specified, then the file will split to the location
% from where it was combined.  For example, if you combined c:\ml\file1 and
% c:\ml\file2 to bigfile, bigfile will be split back into c:\ml\file1 and
% c:\ml\file2.  But if you specify SPLITTO to be c:\temp, then bigfile will
% be split into c:\temp\file1 and c:\temp\file2.
%
% CATORSPLITFILE will return the names of the files that are produced when
% splitting
%
% Example
%    % Combine all the files in the working directory into one
%    CatOrSplitFiles('cat','ConcatenateFilesTest','tst.m','header','no%');
%    % Display the combined file
%    type cattest
%    % Split it back up to reverse the process
%    filenames = CatOrSplitFiles('split','cattest.m', ...
%       'backup','on','header','no%','splitto',pwd);
%    % Look at the directory to see that the backup files have been made
%    dir
%
% Uses
%    ParseVarargin 
%
% Used by
%    SearchReplaceManyGUI
%
% keywords
%    varargin cat concatenate append add split divide break up combine
%    file header
%
% See also:  ParseVarargin SearchReplaceManyGUI
%
%
% It's not fancy, but it works

% Michael Robbins
% michaelNOrobbinsSPAMusenet@yahoo.com
% robbins@bloomberg.net
% TO DO
% FUN parameter is not yet complete

if nargin<1 || length(varargin)<2
    errordlg('This function requires at least 2 inputs.',mfilename);
end;

switch lower(varargin{1})
    case 'cat',
        % IDIOTPROOF INPUTS
        if length(varargin)<3
            errordlg('This function requires at least 3 inputs.',mfilename);
        end;
        filenames = varargin{2};
        target = varargin{3};
        if ~(iscell(filenames) || isstr(filenames)) || ~isstr(target)
            errordlg('This function requires string inputs.',mfilename);
        end;

        % PARAMETER INPUTS
        Prop = {'header','silent','prop'};
        PClass = {'char','char','char'};
        ParseVarargin(varargin,Prop,PClass);

        % TEST
        if iseq(filenames,'ConcatenateFilesTest')
            d=dir;
            filenames={d(3:end).name};
        end;

        % INPUT MUST BE A CELL ARRAY, EVEN IF IT IS ONLY ONE ITEM
        if ~iscell(filenames) filenames = {filenames}; end;

        % DOES TARGET EXIST?
        go=1;
        if exist(target,'file')==2 && ~iseq(silent,'on')
            a=questdlg(['The file, "' target '" exists'],mfilename, ...
                'overwrite','abort','abort');
            go = iseq(a,'overwrite');
        end;
        if go
            % DO WE NEED HEADERS?
            if iseq(header,'off')
                % THIS IS VERY FAST, BUT DOESN'T INCLUDE HEADERS
                filenames=filenames(:);
                s=sprintf('%s+',filenames{:});
                dos(['copy ' s(1:end-1) ' ' target ' > c:\silent.txt.']);
            else
                % SLOWER BUT HAS HEADERS
                FID=FopenWithErrDlg(target,'w');
                for i=1:length(filenames)
                    if exist(filenames{i},'file')==2
                        % PUT IN HEADER TOKEN
                        switch lower(header),
                            case '%', s = repmat('%',1,40);
                            case 'no%', s='';
                        end;
                        [pathstr,name,ext]=fileparts(filenames{i});
                        if isempty(pathstr) pathstr=pwd; end;
                        fprintf(FID,['\n%s %s <%s> %s\n'], ...
                            s,mfilename,fullfile(pathstr,[name ext]),s);
                        % INCLUDE THE FILE
                        FID2 = FopenWithErrDlg(filenames{i},'r');
                        slurp = fscanf(FID2,'%c');
                        fclose(FID2);
                        fprintf(FID,'%c',slurp);
                    else % FILE IS NOT A FILE
                        if ~iseq(silent,'on')
                            warndlg([filenames{i} ' is not a file.'],mfilename);
                        end;
                    end;
                end;
                fclose(FID);
            end;
        end;
    case 'split',
        % IDIOTPROOF INPUTS
        target = varargin{2};
        if ~isstr(target)
            errordlg('This function requires string inputs.',mfilename);
        end;

        % PARAMETER INPUTS
        Prop = {'header','silent','backup','splitto'};
        PClass = {'char','char','char','char'};
        ParseVarargin(varargin,Prop,PClass);

        % GET THE BIG FILE
        FID = FopenWithErrDlg(target,'r');
        slurp = fscanf(FID,'%c');
        fclose(FID);
        
        % EXTRACT TOKENS
        % ON FUNCTION 
        if iseq(header,'fun')
            slurp = ['\n' slurp];
            [b,e]=regexp(slurp,'\n(?!\s*function)');
            [dummy1,dummy2,t]=regexp(slurp,'function ...([^(\s\n]+)');  %%%%%%%%% EXPRESSIONNOT YET FINISHED
        else
            % ON %
            regexstr = ['\n%+\s*' mfilename '\s+<([^>]+)>\s+%+\n'];
            % ON NO%
            if iseq(header,'no%')
                regexstr = strrep(regexstr,'%+','');
            end;
            slurp = sprintf('\n%s\n',slurp);
            [b,e,t]=regexp(slurp,regexstr);
        end;
        
        % IF I'VE GOT `EM
        outi = 0;
        if length(b)>1
            % PAD
            b(end+1)=length(slurp)+1;
            % LOOP THROUGH EACH
            for i=1:length(e)
                % GET STUFF
                filename = slurp(t{i}(1):t{i}(2));
                if ~isnan(splitto)
                    if exist(splitto,'file')==7
                        [pathstr,name,ext]=fileparts(filename);
                        filename = fullfile(splitto,[name ext]);
                    else
                        errordlg([splitto ' is not a valid directory.'], ...
                            mfilename);
                    end;
                end;
                filecontent = slurp(e(i)+1:b(i+1)-1);
                % OVERWRITE?
                go = 1;
                fileexists = exist(filename,'file');
                if  fileexists && iseq(silent,'on')
                    a=questdlg(['The file, "' filename '" exists'], ...
                        mfilename, 'overwrite','abort','abort');
                    go = iseq(a,'overwrite');
                end;
                % GOOD TO GO
                if go
                    % BACKUP
                    if fileexists && ~iseq(backup,'off')
                       dos(['copy "' filename '" "' filename ...
                           '.bak" > c:\silent.txt.']);
                    end;
                    % OUTPUT, FINALLY!
                    outi = outi+1;
                    out{outi} = filename;
                    FID = FopenWithErrDlg(filename,'w');
                    fprintf(FID,'%c',filecontent);
                    fclose(FID);
                end;
            end;
        else
            errordlg(['Nothing to do. ' target ...
                ' contains only one file.'],mfilename);
        end;
    otherwise,
        errordlg('Bad action.',mfilename);
end;

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function out = iseq(str,val)
% ISEQ Tests if two strings are equal

%if ~iscell(str) str = {str}; end;
%if ~iscell(val) val = {val}; end;
%out = ismember(lower(str),lower(val));

% IF ONE IS A STRING
strisstr = isstr(str) || iscell(str);
valisstr = isstr(val) || iscel(val);
if strisstr || valisstr
    % IF THEY'RE BOTH STRINGS
    if strisstr && valisstr
        out = ~isempty(strmatch(lower(str),lower(val),'exact'));
    else
        out = logical(0);
    end;
else
    out = all(str==val);
end;

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function FID = FopenWithErrDlg(filename,a)
% FOPENWITHERRDLG opens a file and produces an error dialog if there's a
% problem with the process

FID=fopen(filename,a);
if FID == -1 
    switch a(1)
        case 'w', action = 'writing';
        case 'a', action = 'writing';
        case 'r', action = 'reading';
    end;
    errordlg(['Error opening ' filename ' for ' action],mfilename);
end;

Contact us at files@mathworks.com