image thumbnail
from crap: a pedestrian absolute folder/file path creator by us
crap creates absolute paths to folders and/or files

[p,id,enam]=crap(varargin)
%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
%-------------------------------------------------------------------------------

Contact us at files@mathworks.com