Home > io > getFullPath.m

getFullPath

PURPOSE ^

getFullPath - Get absolute canonical path of a file or folder

SYNOPSIS ^

function File = getFullPath(File, Style)

DESCRIPTION ^

 getFullPath - Get absolute canonical path of a file or folder
 Absolute path names are safer than relative paths, when e.g. a GUI or TIMER
 callback changes the current directory. Only canonical paths without "." and
 ".." can be recognized uniquely.
 Long path names (>259 characters) require a magic initial key "\\?\" to be
 handled by Windows API functions, e.g. for Matlab's FOPEN, DIR and EXIST.

 FullName = getFullPath(Name, Style)
 INPUT:
   Name:  String or cell string, absolute or relative name of a file or
          folder. The path need not exist. Unicode strings, UNC paths and long
          names are supported.
   Style: Style of the output as string, optional, default: 'auto'.
          'auto': Add '\\?\' or '\\?\UNC\' for long names on demand.
          'lean': Magic string is not added.
          'fat':  Magic string is added for short names also.
          The Style is ignored when not running under Windows.

 OUTPUT:
   FullName: Absolute canonical path name as string or cell string.
          For empty strings the current directory is replied.
          '\\?\' or '\\?\UNC' is added on demand.

 NOTE: The M- and the MEX-version create the same results, the faster MEX
   function works under Windows only.
   Some functions of the Windows-API still do not support long file names.
   E.g. the Recycler and the Windows Explorer fail even with the magic '\\?\'
   prefix. Some functions of Matlab accept 260 characters (value of MAX_PATH),
   some at 259 already. Don't blame me.
   The 'fat' style is useful e.g. when Matlab's DIR command is called for a
   folder with les than 260 characters, but together with the file name this
   limit is exceeded. Then "dir(getFullPath([folder, '\*.*], 'fat'))" helps.

 EXAMPLES:
   cd(tempdir);                    % Assumed as 'C:\Temp' here
   getFullPath('File.Ext')         % 'C:\Temp\File.Ext'
   getFullPath('..\File.Ext')      % 'C:\File.Ext'
   getFullPath('..\..\File.Ext')   % 'C:\File.Ext'
   getFullPath('.\File.Ext')       % 'C:\Temp\File.Ext'
   getFullPath('*.txt')            % 'C:\Temp\*.txt'
   getFullPath('..')               % 'C:\'
   getFullPath('..\..\..')         % 'C:\'
   getFullPath('Folder\')          % 'C:\Temp\Folder\'
   getFullPath('D:\A\..\B')        % 'D:\B'
   getFullPath('\\Server\Folder\Sub\..\File.ext')
                                   % '\\Server\Folder\File.ext'
   getFullPath({'..', 'new'})      % {'C:\', 'C:\Temp\new'}
   getFullPath('.', 'fat')         % '\\?\C:\Temp\File.Ext'

 COMPILE:
   Automatic: InstallMex getFullPath.c uTest_getFullPath
   Manual:    mex -O getFullPath.c
   Download:  http://www.n-simon.de/mex
 Run the unit-test uTest_getFullPath after compiling.

 Tested: Matlab 6.5, 7.7, 7.8, 7.13, WinXP/32, Win7/64
         Compiler: LCC2.4/3.8, BCC5.5, OWC1.8, MSVC2008/2010
 Assumed Compatibility: higher Matlab versions
 Author: Jan Simon, Heidelberg, (C) 2009-2013 matlab.THISYEAR(a)nMINUSsimon.de

 See also: CD, FULLFILE, FILEPARTS.

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SOURCE CODE ^

0001 function File = getFullPath(File, Style)
0002 % getFullPath - Get absolute canonical path of a file or folder
0003 % Absolute path names are safer than relative paths, when e.g. a GUI or TIMER
0004 % callback changes the current directory. Only canonical paths without "." and
0005 % ".." can be recognized uniquely.
0006 % Long path names (>259 characters) require a magic initial key "\\?\" to be
0007 % handled by Windows API functions, e.g. for Matlab's FOPEN, DIR and EXIST.
0008 %
0009 % FullName = getFullPath(Name, Style)
0010 % INPUT:
0011 %   Name:  String or cell string, absolute or relative name of a file or
0012 %          folder. The path need not exist. Unicode strings, UNC paths and long
0013 %          names are supported.
0014 %   Style: Style of the output as string, optional, default: 'auto'.
0015 %          'auto': Add '\\?\' or '\\?\UNC\' for long names on demand.
0016 %          'lean': Magic string is not added.
0017 %          'fat':  Magic string is added for short names also.
0018 %          The Style is ignored when not running under Windows.
0019 %
0020 % OUTPUT:
0021 %   FullName: Absolute canonical path name as string or cell string.
0022 %          For empty strings the current directory is replied.
0023 %          '\\?\' or '\\?\UNC' is added on demand.
0024 %
0025 % NOTE: The M- and the MEX-version create the same results, the faster MEX
0026 %   function works under Windows only.
0027 %   Some functions of the Windows-API still do not support long file names.
0028 %   E.g. the Recycler and the Windows Explorer fail even with the magic '\\?\'
0029 %   prefix. Some functions of Matlab accept 260 characters (value of MAX_PATH),
0030 %   some at 259 already. Don't blame me.
0031 %   The 'fat' style is useful e.g. when Matlab's DIR command is called for a
0032 %   folder with les than 260 characters, but together with the file name this
0033 %   limit is exceeded. Then "dir(getFullPath([folder, '\*.*], 'fat'))" helps.
0034 %
0035 % EXAMPLES:
0036 %   cd(tempdir);                    % Assumed as 'C:\Temp' here
0037 %   getFullPath('File.Ext')         % 'C:\Temp\File.Ext'
0038 %   getFullPath('..\File.Ext')      % 'C:\File.Ext'
0039 %   getFullPath('..\..\File.Ext')   % 'C:\File.Ext'
0040 %   getFullPath('.\File.Ext')       % 'C:\Temp\File.Ext'
0041 %   getFullPath('*.txt')            % 'C:\Temp\*.txt'
0042 %   getFullPath('..')               % 'C:\'
0043 %   getFullPath('..\..\..')         % 'C:\'
0044 %   getFullPath('Folder\')          % 'C:\Temp\Folder\'
0045 %   getFullPath('D:\A\..\B')        % 'D:\B'
0046 %   getFullPath('\\Server\Folder\Sub\..\File.ext')
0047 %                                   % '\\Server\Folder\File.ext'
0048 %   getFullPath({'..', 'new'})      % {'C:\', 'C:\Temp\new'}
0049 %   getFullPath('.', 'fat')         % '\\?\C:\Temp\File.Ext'
0050 %
0051 % COMPILE:
0052 %   Automatic: InstallMex getFullPath.c uTest_getFullPath
0053 %   Manual:    mex -O getFullPath.c
0054 %   Download:  http://www.n-simon.de/mex
0055 % Run the unit-test uTest_getFullPath after compiling.
0056 %
0057 % Tested: Matlab 6.5, 7.7, 7.8, 7.13, WinXP/32, Win7/64
0058 %         Compiler: LCC2.4/3.8, BCC5.5, OWC1.8, MSVC2008/2010
0059 % Assumed Compatibility: higher Matlab versions
0060 % Author: Jan Simon, Heidelberg, (C) 2009-2013 matlab.THISYEAR(a)nMINUSsimon.de
0061 %
0062 % See also: CD, FULLFILE, FILEPARTS.
0063 
0064 % $JRev: R-G V:032 Sum:7Xd/JS0+yfax Date:15-Jan-2013 01:06:12 $
0065 % $License: BSD (use/copy/change/redistribute on own risk, mention the author) $
0066 % $UnitTest: uTest_getFullPath $
0067 % $File: Tools\GLFile\getFullPath.m $
0068 % History:
0069 % 001: 20-Apr-2010 22:28, Successor of Rel2AbsPath.
0070 % 010: 27-Jul-2008 21:59, Consider leading separator in M-version also.
0071 % 011: 24-Jan-2011 12:11, Cell strings, '~File' under linux.
0072 %      Check of input types in the M-version.
0073 % 015: 31-Mar-2011 10:48, BUGFIX: Accept [] as input as in the Mex version.
0074 %      Thanks to Jiro Doke, who found this bug by running the test function for
0075 %      the M-version.
0076 % 020: 18-Oct-2011 00:57, BUGFIX: Linux version created bad results.
0077 %      Thanks to Daniel.
0078 % 024: 10-Dec-2011 14:00, Care for long names under Windows in M-version.
0079 %      Improved the unittest function for Linux. Thanks to Paul Sexton.
0080 % 025: 09-Aug-2012 14:00, In MEX: Paths starting with "\\" can be non-UNC.
0081 %      The former version treated "\\?\C:\<longpath>\file" as UNC path and
0082 %      replied "\\?\UNC\?\C:\<longpath>\file".
0083 % 032: 12-Jan-2013 21:16, 'auto', 'lean' and 'fat' style.
0084 
0085 % Initialize: ==================================================================
0086 % Do the work: =================================================================
0087 
0088 % #############################################
0089 % ### USE THE MUCH FASTER MEX ON WINDOWS!!! ###
0090 % #############################################
0091 
0092 % Difference between M- and Mex-version:
0093 % - Mex does not work under MacOS/Unix.
0094 % - Mex calls Windows API function getFullPath.
0095 % - Mex is much faster.
0096 
0097 % Magix prefix for long Windows names:
0098 if nargin < 2
0099     Style = 'auto';
0100 end
0101 
0102 % Handle cell strings: NOTE: It is faster to create a function
0103 % @cell\getFullPath.m under Linux, but under Windows this would shadow the
0104 % fast C-Mex.
0105 if isa(File, 'cell')
0106     for iC = 1:numel(File)
0107         File{iC} = getFullPath(File{iC}, Style);
0108     end
0109     return;
0110 end
0111 
0112 % Check this once only:
0113 isWIN    = strncmpi(computer, 'PC', 2);
0114 MAX_PATH = 260;
0115 
0116 % Warn once per session (disable this under Linux/MacOS):
0117 persistent hasDataRead
0118 if isempty(hasDataRead)
0119     % Test this once only - there is no relation to the existence of
0120     % DATAREAD!
0121     %if isWIN
0122     %   Show a warning, if the slower Matlab version is used - commented,
0123     %   because this is not a problem and it might be even useful when the
0124     %   MEX-folder is not inlcuded in the path yet.
0125     %   warning('JSimon:getFullPath:NoMex', ...
0126     %      ['getFullPath: Using slow Matlab-version instead of fast Mex.',
0127     %      ...
0128     %       char(10), 'Compile: InstallMex getFullPath.c']);
0129     %end
0130     
0131     % DATAREAD is deprecated in 2011b, but still available. In Matlab 6.5,
0132     % REGEXP does not know the 'split' command, therefore DATAREAD is
0133     % preferred:
0134     hasDataRead = ~isempty(which('dataread'));
0135 end
0136 
0137 if isempty(File)  % Accept empty matrix as input:
0138     if ischar(File) || isnumeric(File)
0139         File = cd;
0140         return;
0141     else
0142         error(['JSimon:', mfilename, ':BadTypeInput1'], ...
0143             ['*** ', mfilename, ': Input must be a string or cell string']);
0144     end
0145 end
0146 
0147 if ischar(File) == 0  % Non-empty inputs must be strings
0148     error(['JSimon:', mfilename, ':BadTypeInput1'], ...
0149         ['*** ', mfilename, ': Input must be a string or cell string']);
0150 end
0151 
0152 if isWIN  % Windows: --------------------------------------------------------
0153     FSep = '\';
0154     File = strrep(File, '/', FSep);
0155     
0156     % Remove the magic key on demand, it is appended finally again:
0157     if strncmp(File, '\\?\', 4)
0158         if strncmpi(File, '\\?\UNC\', 8)
0159             File = ['\', File(7:length(File))];  % Two leading backslashes!
0160         else
0161             File = File(5:length(File));
0162         end
0163     end
0164     
0165     isUNC   = strncmp(File, '\\', 2);
0166     FileLen = length(File);
0167     if isUNC == 0                        % File is not a UNC path
0168         % Leading file separator means relative to current drive or base
0169         % folder:
0170         ThePath = cd;
0171         if File(1) == FSep
0172             if strncmp(ThePath, '\\', 2)   % Current directory is a UNC path
0173                 sepInd  = strfind(ThePath, '\');
0174                 ThePath = ThePath(1:sepInd(4));
0175             else
0176                 ThePath = ThePath(1:3);     % Drive letter only
0177             end
0178         end
0179         
0180         if FileLen < 2 || File(2) ~= ':'  % Does not start with drive letter
0181             if ThePath(length(ThePath)) ~= FSep
0182                 if File(1) ~= FSep
0183                     File = [ThePath, FSep, File];
0184                 else                        % File starts with separator:
0185                     File = [ThePath, File];
0186                 end
0187             else                           % Current path ends with separator:
0188                 if File(1) ~= FSep
0189                     File = [ThePath, File];
0190                 else                        % File starts with separator:
0191                     ThePath(length(ThePath)) = [];
0192                     File = [ThePath, File];
0193                 end
0194             end
0195             
0196         elseif FileLen == 2 && File(2) == ':'   % "C:" current directory on C!
0197             % "C:" is the current directory on the C-disk, even if the
0198             % current directory is on another disk! This was ignored in
0199             % Matlab 6.5, but modern versions considers this strange
0200             % behaviour.
0201             if strncmpi(ThePath, File, 2)
0202                 File = ThePath;
0203             else
0204                 try
0205                     File = cd(cd(File));
0206                 catch    % No MException to support Matlab6.5...
0207                     if exist(File, 'dir')  % No idea what could cause an error then!
0208                         rethrow(lasterror);
0209                     else  % Reply "K:\" for not existing disk:
0210                         File = [File, FSep];
0211                     end
0212                 end
0213             end
0214         end
0215     end
0216     
0217 else         % Linux, MacOS: ---------------------------------------------------
0218     FSep = '/';
0219     File = strrep(File, '\', FSep);
0220     
0221     if strcmp(File, '~') || strncmp(File, '~/', 2)  % Home directory:
0222         HomeDir = getenv('HOME');
0223         if ~isempty(HomeDir)
0224             File(1) = [];
0225             File    = [HomeDir, File];
0226         end
0227         
0228     elseif strncmpi(File, FSep, 1) == 0
0229         % Append relative path to current folder:
0230         ThePath = cd;
0231         if ThePath(length(ThePath)) == FSep
0232             File = [ThePath, File];
0233         else
0234             File = [ThePath, FSep, File];
0235         end
0236     end
0237 end
0238 
0239 % Care for "\." and "\.." - no efficient algorithm, but the fast Mex is
0240 % recommended at all!
0241 if ~isempty(strfind(File, [FSep, '.']))
0242     if isWIN
0243         if strncmp(File, '\\', 2)  % UNC path
0244             index = strfind(File, '\');
0245             if length(index) < 4    % UNC path without separator after the folder:
0246                 return;
0247             end
0248             Drive            = File(1:index(4));
0249             File(1:index(4)) = [];
0250         else
0251             Drive     = File(1:3);
0252             File(1:3) = [];
0253         end
0254     else  % Unix, MacOS:
0255         isUNC   = false;
0256         Drive   = FSep;
0257         File(1) = [];
0258     end
0259     
0260     hasTrailFSep = (File(length(File)) == FSep);
0261     if hasTrailFSep
0262         File(length(File)) = [];
0263     end
0264     
0265     if hasDataRead
0266         if isWIN  % Need "\\" as separator:
0267             C = dataread('string', File, '%s', 'delimiter', '\\');  %#ok<REMFF1>
0268         else
0269             C = dataread('string', File, '%s', 'delimiter', FSep);  %#ok<REMFF1>
0270         end
0271     else  % Use the slower REGEXP, when DATAREAD is not available anymore:
0272         C = regexp(File, FSep, 'split');
0273     end
0274     
0275     % Remove '\.\' directly without side effects:
0276     C(strcmp(C, '.')) = [];
0277     
0278     % Remove '\..' with the parent recursively:
0279     R = 1:length(C);
0280     for dd = reshape(find(strcmp(C, '..')), 1, [])
0281         index    = find(R == dd);
0282         R(index) = [];
0283         if index > 1
0284             R(index - 1) = [];
0285         end
0286     end
0287     
0288     if isempty(R)
0289         File = Drive;
0290         if isUNC && ~hasTrailFSep
0291             File(length(File)) = [];
0292         end
0293         
0294     elseif isWIN
0295         % If you have CStr2String, use the faster:
0296         %   File = CStr2String(C(R), FSep, hasTrailFSep);
0297         File = sprintf('%s\\', C{R});
0298         if hasTrailFSep
0299             File = [Drive, File];
0300         else
0301             File = [Drive, File(1:length(File) - 1)];
0302         end
0303         
0304     else  % Unix:
0305         File = [Drive, sprintf('%s/', C{R})];
0306         if ~hasTrailFSep
0307             File(length(File)) = [];
0308         end
0309     end
0310 end
0311 
0312 % "Very" long names under Windows:
0313 if isWIN
0314     if ~ischar(Style)
0315         error(['JSimon:', mfilename, ':BadTypeInput2'], ...
0316             ['*** ', mfilename, ': Input must be a string or cell string']);
0317     end
0318     
0319     if (strncmpi(Style, 'a', 1) && length(File) >= MAX_PATH) || ...
0320             strncmpi(Style, 'f', 1)
0321         % Do not use [isUNC] here, because this concerns the input, which
0322         % can '.\File', while the current directory is an UNC path.
0323         if strncmp(File, '\\', 2)  % UNC path
0324             File = ['\\?\UNC', File(2:end)];
0325         else
0326             File = ['\\?\', File];
0327         end
0328     end
0329 end
0330 
0331 % return;
0332 end

Generated by m2html © 2005