%CRAP CReate Absolute Path to a folder or file
% CRAP creates clean absolute paths for existing
% - absolute paths to folders and/or files
% - relative paths to folders and/or files
% which may include any valid combination of './' or '../' syntax
% absolute paths are created based
% - on the current folder (default root)
% - an optional root folder given as the second argument
% CRAP returns the absolute path and an optional argument,
% which shows the result of the operation
%
%SYNTAX
% [AP,R] = CRAP(FOLDER|FILE)
% [AP,R] = CRAP(FOLDER|FILE,ROOT)
% [AP,R] = CRAP({'F1','F2',...,'Fx'},ROOT)
% [AP,R] = CRAP({'F1','F2'...'Fx'},{'R1','R2'...'Rx'})
% [AP,R] = CRAP(N,...)
%
%INPUT
% F|F a character string or a cell of character strings
% R a character string or a cell of character strings
% N if the first arg is numeric, runtime messages are not shown
%
%OUTPUT
% AP absolute path of the FOLDER|FILE
% R result
% 0 AP is valid but does NOT exist
% 1 AP is a folder
% 2 AP is a file
%
%NOTES
% - if cells are used, the number of Rs
% must match the number of Fs|Fs or be 1 (one)
% - if F|F is a cell and only one R is used, it
% may be a character string
% - if the input are cells, the output are also
% cells
% - leading \\ are preserved in UNC paths
%
%EXAMPLE
% rd=sprintf('%s/toolbox/matlab/datafun',matlabroot);
% od=cd(rd);
% ep={
% [rd,'/../']
% '../datatypes/@char'
% '../../matlab/datatypes/../datatypes/@char'
% '../../matlab/datafun/../../matlab/elmat/../elmat/magic.m'
% };
% for i=1:numel(ep)
% ap=crap(ep{i});
% disp(ap)
% end
% [ap,ar]=crap(ep);
% disp(ap);
% cd(od);
% [ap,ar]=crap({'bin','bin'},matlabroot)
% [ap,ar]=crap({'bin','bin'},{matlabroot,matlabroot})
% created:
% us 12-Jan-1989
% modified:
% us 29-Jan-2008 19:41:46
%-------------------------------------------------------------------------------
function [p,id,enam]=crap(varargin)
if nargout
p='';
id=0;
end
% check arguments
if ~usejava('jvm')
disp(sprintf('CRAP> java engine not enabled!'));
return;
end
if nargin < 1 ||...
isempty(varargin{1})
help(mfilename);
return;
end
% get/check input
[parg,rarg,narg,opt]=ini_arg(varargin{:});
if ~narg
return;
end
% run main engine
p=cell(narg,1);
id=cell(narg,1);
for i=1:numel(parg)
[p{i},id{i},enam]=run_crap(parg{i},rarg{i},opt);
end
if narg == 1
p=p{1};
id=id{1};
end
end
%-------------------------------------------------------------------------------
function [parg,rarg,narg,opt]=ini_arg(varargin)
opt.mflg=true; % show messages
voff=1;
tnarg=1;
if isnumeric(varargin{1})
opt.mflg=false;
voff=2;
tnarg=2;
end
parg=varargin{voff};
if ~iscell(parg)
parg={parg};
end
narg=numel(parg);
od=cd;
rarg=repmat({od},narg,1);
if nargin > tnarg
if ~iscell(varargin{voff+1})
rarg={varargin{voff+1}};
else
rarg=varargin{voff+1};
end
if numel(rarg) == 1
rarg=repmat(rarg,narg,1);
end
if numel(rarg) ~= narg
txt={
sprintf('CRAP> input arguments do not match!')
sprintf(' # roots must be # paths or 1')
sprintf(' # paths %5d',narg)
sprintf(' # roots %5d',numel(rarg))
};
disp(char(txt));
narg=0;
return;
end
ix=cellfun(@isempty,rarg);
rarg(ix)={od};
end
end
%-------------------------------------------------------------------------------
function [p,id,enam]=run_crap(parg,rarg,opt)
% use forward slashes only
% - simplifies rex expressions
% - except for UNC
if parg(end)==':' % DOS(!)
parg(end+1)='/';
end
carg={parg;rarg};
isunc=strncmp('\\',carg,2);
carg=strrep(carg,'\','/');
carg(isunc)=cellfun(@(x) ['\\',x(3:end)],...
carg(isunc),...
'uni',false);
% remove multiple path separators
carg=regexprep(carg,'(/+)','/');
[p,ap]=carg{:};
% erroneous behavior in java (last reported for 1.6.0)
% - cannot correctly resolve top level paths of the form
% /folder
% therefore, the volume/drive name must be added
if ispc &&...
p(1) == '/' &&...
(numel(p) == 1 || p(2) ~= '/')
vd=cd;
rx=strfind(vd,':');
p=[vd(1:rx),p];
end
% create absolute path if necessary
[fp,id]=chk_path(p);
if ~id(1)
[ax,as]=split_path(ap);
[ps,ps]=split_path(p);
[px,ps]=get_rel(ps);
p=set_abs(as,ps,px);
[fp,id]=chk_path(p);
end
% check existence
if ~id(4) ||...
~id(1)
if opt.mflg
disp(sprintf('CRAP> path/file does not exist:\n %s\n',p));
end
enam=p;
p='';
id=0;
return;
else
p=char(fp.getCanonicalPath);
isunc=strncmp('\\',p,2);
if isunc
p(3:end)=strrep(p(3:end),'\','/');
else
p=strrep(p,'\','/');
end
end
% set file type
if id(2) &&...
p(end)~='/'
p(end+1)='/';
elseif ~id(2) &&...
p(end)=='/'
p(end)='';
end
id=id(3)+1;
enam=p;
end
%-------------------------------------------------------------------------------
function [fp,ia]=chk_path(fp)
import java.io.*;
fp=File(fp);
ia=[
fp.isAbsolute
fp.isDirectory
fp.isFile
fp.exists
];
end
%-------------------------------------------------------------------------------
function [fx,fs]=split_path(fp)
if isempty(fp)
err('CRAP> empty path/file','');
end
[fx,fs]=regexp(fp,'(/)','start','split');
if ~isempty(fx)
fx=~cellfun(@isempty,fs);
fs=fs(fx);
end
end
%-------------------------------------------------------------------------------
function [ixr,fp]=get_rel(fp)
fx=regexp(fp,'^(\.){3,}$');
fn=cellfun(@isempty,fx);
if ~fn(end)
err('CRAP> invalid path:\n%s/',sprintf('%s/',fp{:}));
end
fp=fp(fn);
ixa=strcmp(fp,'.');
if any(ixa)
if ~ixa(1) ||...
sum(ixa) > 1
err('CRAP> invalid path:\n%s',sprintf('%s/',fp{:}));
else
fp=fp(2:end);
end
end
ixr=strcmp(fp,'..');
ib=strfind(ixr,[1,0])+1;
if ~isempty(ib)
ixr(ib(1):end)=false;
end
end
%-------------------------------------------------------------------------------
function p=set_abs(fs,ps,px)
p='';
ix=1:numel(fs)-sum(px);
if ~isempty(ix)
p=sprintf('%s/',fs{ix},ps{~px});
p(end)='';
end
end
%-------------------------------------------------------------------------------
function err(fmt,str)
error(fmt,str);
end
%-------------------------------------------------------------------------------