2%> Return the Get absolute canonical path of a file or folder.<br>
5%> Absolute path names are safer than relative paths, e.g., when
6%> a GUI or TIMER callback changes the current directory.<br>
7%> Only canonical paths without ``
"."`` and ``
".."``
8%> can be recognized uniquely.<br>
11%> Long path names (>259 characters) require a magic initial
12%> key ``
"\\?\"`` to be handled by Windows API functions, e.g. for
13%> MATLAB intrinsic routines ``fopen()``, ``dir()`` and ``exist()``.<br>
16%> Some functions of the Windows-API still do not support long file names.<br>
17%> For example, the Recycler and the Windows Explorer fail even with the magic ``'\\?\'`` prefix.<br>
18%> Some functions of MATLAB accept 260 characters (value of MAX_PATH), some at 259 already.<br>
19%> The ``'fat'`` style is useful e.g., when MATLAB ``dir()`` command is called for a folder
20%> with less than ``260`` characters, but together with the file name this limit is exceeded.<br>
21%> Then, ``"dir(pm.sys.path.abs([folder,
'\*.*'],
'fat'))
"`` helps.<br>
24%> A MEX version of this function developed by Jan Simon performs much faster on Windows.<br>
25%> Difference between M- and Mex-version:<br>
27%> <li> Mex does not work under MacOS/Unix.
28%> <li> Mex calls Windows API function pm.sys.path.abs.
29%> <li> Mex is much faster.
32%> \param[in] path : The input argument that can be either,<br>
34%> <li> a scalar MATLAB string or character, or,
35%> <li> a MATLAB string or cell array of strings or character values,
37%> containing the absolute or relative name(s) of a file(s) or folder(s).<br>
38%> The path need not exist. Unicode strings, UNC paths and long
39%> names are supported.<br>
40%> \param[in] style : The optional input scalar MATLAB string or character,
41%> containing the style of the output as string.<br>
42%> The following values are possible:<br>
44%> <li> ``'auto'`` : Add ``'\\?\'`` or ``'\\?\UNC\'`` for long names on demand.
45%> <li> ``'lean'`` : Magic string is not added.
46%> <li> ``'fat'`` : Magic string is added for short names also.
48%> The input ``style`` is ignored when not running under Windows.<br>
49%> (**optional**, default = 'auto')
52%> ``path`` : The output scalar MATLAB character string
53%> containing the absolute path corresponding to the input path.<br>
54%> If the input ``path`` is empty, ``pathAbs`` is the current directory.<br>
55%> The optional prefixes ``'\\?\'`` or ``'\\?\UNC'`` are added on demand
56%> as requested by the optional input argument ``style``.<br>
61%> path = pm.sys.path.abs(file)
62%> path = pm.sys.path.abs(file, style)
67%> [A collection of MATLAB mex files for system path manipulation](http://www.n-simon.de/mex)<br>
72%> cd(tempdir); % Assumed as 'C:\Temp' here
73%> pm.sys.path.abs('File.Ext') % 'C:\Temp\File.Ext'
74%> pm.sys.path.abs('..\File.Ext') % 'C:\File.Ext'
75%> pm.sys.path.abs('..\..\File.Ext') % 'C:\File.Ext'
76%> pm.sys.path.abs('.\File.Ext') % 'C:\Temp\File.Ext'
77%> pm.sys.path.abs('*.txt') % 'C:\Temp\*.txt'
78%> pm.sys.path.abs('..') % 'C:\'
79%> pm.sys.path.abs('..\..\..') % 'C:\'
80%> pm.sys.path.abs('Folder\') % 'C:\Temp\Folder\'
81%> pm.sys.path.abs('D:\A\..\B') % 'D:\B'
82%> pm.sys.path.abs('\\Server\Folder\Sub\..\File.ext') % '\\Server\Folder\File.ext'
83%> pm.sys.path.abs({'..', 'new'}) % {'C:\', 'C:\Temp\new'}
84%> pm.sys.path.abs(["..
", "new"]) % ["C:\
", "C:\Temp\new
"]
85%> pm.sys.path.abs('.', 'fat') % '\\?\C:\Temp\File.Ext'
90%> \include{lineno} example/sys/path/abs/main.m
92%> \include{lineno} example/sys/path/abs/main.out.m
96%> This file is based on a functionality originally developed by Jan Simon.
99%> Copyright (c) 2016, Jan Simon
100%> All rights reserved.
102%> Redistribution and use in source and binary forms, with or without
103%> modification, are permitted provided that the following conditions are met:
105%> * Redistributions of source code must retain the above copyright notice, this
106%> list of conditions and the following disclaimer.
108%> * Redistributions in binary form must reproduce the above copyright notice,
109%> this list of conditions and the following disclaimer in the documentation
110%> and/or other materials provided with the distribution
111%> * Neither the name of nor the names of its
112%> contributors may be used to endorse or promote products derived from this
113%> software without specific prior written permission.
114%> THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS
"
115%> AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
116%> IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
117%> DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
118%> FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
119%> DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
120%> SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
121%> CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
122%> OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
123%> OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
125%> Tested: MATLAB 2009a, 2015b(32/64), 2016b, 2018b, Win7/10
126%> Compiler: LCC2.4/3.8, BCC5.5, OWC1.8, MSVC2008/2010
127%> Assumed Compatibility: higher MATLAB versions
128%> Author: Jan Simon, Heidelberg, (C) 2009-2019 matlab.2010(a)n(MINUS)simon.de
130%> $JRev: R-M V:038 Sum:C/6JMzUYsYsc Date:19-May-2019 17:25:55 $
131%> $License: BSD (use/copy/change/redistribute on own risk, mention the author) $
132%> $UnitTest: uTest_getFullPath $
133%> $File: Tools\GLFile\pm.sys.path.abs.m $
135%> 001: 20-Apr-2010 22:28, Successor of Rel2AbsPath.
136%> 010: 27-Jul-2008 21:59, Consider leading separator in M-version also.
137%> 011: 24-Jan-2011 12:11, Cell strings, '~File' under linux.
138%> Check of input types in the M-version.
139%> 015: 31-Mar-2011 10:48, BUGFIX: Accept [] as input as in the Mex version.
140%> Thanks to Jiro Doke, who found this bug by running the test function for
142%> 020: 18-Oct-2011 00:57, BUGFIX: Linux version created bad results.
144%> 024: 10-Dec-2011 14:00, Care for long names under Windows in M-version.
145%> Improved the unittest function for Linux. Thanks to Paul Sexton.
146%> 025: 09-Aug-2012 14:00, In MEX: Paths starting with "\\
" can be non-UNC.
147%> The former version treated "\\?\C:\<longpath>\file
" as UNC path and
148%> replied "\\?\UNC\?\C:\<longpath>\file
".
149%> 032: 12-Jan-2013 21:16, 'auto', 'lean' and 'fat' style.
150%> 038: 19-May-2019 17:25, BUGFIX, Thanks HHang Li, "File(7:...
" -> "File(8:...
"
155%> \JoshuaOsborne, May 21 2024, 5:15 AM, University of Texas at Arlington<br>
156%> \FatemehBagheri, May 20 2024, 1:25 PM, NASA Goddard Space Flight Center (GSFC), Washington, D.C.<br>
157%> \AmirShahmoradi, May 16 2016, 9:03 AM, Oden Institute for Computational Engineering and Sciences (ICES), UT Austin<br>
158function path = abs(path, style)
161 %%%% Set the magic prefix for long Windows names.
167 style = convertStringsToChars(string(style));
170 if 1 < pm.array.len(path)
172 for iell = 1 : numel(path)
173 path{iell} = string(pm.sys.path.abs(path{iell}, style));
176 for iell = 1 : numel(path)
177 path(iell) = string(pm.sys.path.abs(path(iell), style));
182 path = convertStringsToChars(string(path));
186 %%%% Check this once only.
189 isWindows = strncmpi(computer, 'PC', 2);
193 %%%% Warn once per session (disable this under Linux/MacOS).
196 persistent hasDataRead
197 if isempty(hasDataRead)
198 % Test this once only - there is no relation to the existence of DATAREAD!
200 % Show a warning, if the slower MATLAB version is used - commented, because
201 % this is not a problem and it might be even useful when the MEX-folder is
202 % not included in the path yet.
203 % warning ( newline ...
204 % + 'pm.sys.path.abs:NoMex', ...
205 % + ['pm.sys.path.abs: Using slow MATLAB-version instead of fast Mex.', ...
206 % + char(10), 'Compile: InstallMex pm.sys.path.abs.c'] ...
210 % DATAREAD is deprecated in 2011b, but still available. In MATLAB 6.5, REGEXP
211 % does not know the 'split' command, therefore DATAREAD is preferred.
212 hasDataRead = ~isempty(which('dataread'));
215 if isempty(path) % Accept empty matrix as input.
216 if ischar(path) || isnumeric(path)
221 + "A non-empty input argument `path` must be a
string, character, or array of such values.
" + newline ...
228 % Non-empty inputs must be strings
230 + "A non-empty input argument `path` must be a
string, character, or array of such values.
" + newline ...
235 if isWindows % Windows: --------------------------------------------------------
238 path = strrep(path, '/', dirsep);
241 %%%% Remove the magic key on demand, it is appended finally again.
244 if strncmp(path, '\\?\', 4)
245 if strncmpi(path, '\\?\UNC\', 8)
246 % [BUGFIX] 19-May-2019, Thanks HHang Li, "path(7:...
" -> "path(8:...
"
247 path = ['\', path(8 : length(path))]; % Two leading backslashes!
249 path = path(5 : length(path));
253 isUNC = strncmp(path, '\\', 2);
254 FileLen = length(path);
255 if isUNC == 0 % path is not a UNC path
258 %%%% Leading file separator means relative to current drive or base folder.
263 if strncmp(ThePath, '\\', 2)
264 % Current directory is a UNC path.
265 sepInd = strfind(ThePath, '\');
266 ThePath = ThePath(1 : sepInd(4));
269 ThePath = ThePath(1 : 3);
273 if FileLen < 2 || path(2) ~= ':'
274 % Does not start with drive letter.
275 if ThePath(length(ThePath)) ~= dirsep
277 path = [ThePath, dirsep, path];
279 % path starts with separator.
280 path = [ThePath, path];
283 % Current path ends with separator.
285 path = [ThePath, path];
287 % path starts with separator.
288 ThePath(length(ThePath)) = [];
289 path = [ThePath, path];
292 elseif FileLen == 2 && path(2) == ':'
293 % "C:
" current directory on C!
294 % "C:
" is the current directory on the C-disk, even if the current
295 % directory is on another disk! This was ignored in MATLAB 6.5, but
296 % modern versions considers this strange behaviour.
297 if strncmpi(ThePath, path, 2)
305 if exist(path, 'dir')
306 % No idea what could cause an error then!
309 % Reply "K:\
" for not existing disk.
310 path = [path, dirsep];
317 else % Linux, MacOS: ---------------------------------------------------
320 path = strrep(path, '\', dirsep);
322 if strcmp(path, '~') || strncmp(path, '~/', 2)
324 homedir = getenv('HOME');
327 path = [homedir, path];
329 elseif strncmpi(path, dirsep, 1) == 0
330 % Append relative path to current folder.
332 if ThePath(length(ThePath)) == dirsep
333 path = [ThePath, path];
335 path = [ThePath, dirsep, path];
342 %%%% Care for "\.
" and "\..
" - no efficient algorithm, but the fast Mex is recommended at all!
345 if ~isempty(strfind(path, [dirsep, '.']))
348 if strncmp(path, '\\', 2)
350 index = strfind(path, '\');
352 % UNC path without separator after the folder.
355 drive = path(1:index(4));
356 path(1:index(4)) = [];
368 hasTrailFSep = (path(length(path)) == dirsep);
370 path(length(path)) = [];
375 % Need "\\
" as separator.
376 C = dataread('string', path, '%s', 'delimiter', '\\'); %#ok<REMFF1>
378 C = dataread('string', path, '%s', 'delimiter', dirsep); %#ok<REMFF1>
381 % Use the slower REGEXP, when DATAREAD is not available anymore.
382 C = regexp(path, dirsep, 'split');
385 % Remove '\.\' directly without side effects.
386 C(strcmp(C, '.')) = [];
388 % Remove '\..' with the parent recursively.
390 for dd = reshape(find(strcmp(C, '..')), 1, [])
391 index = find(R == dd);
400 if isUNC && ~hasTrailFSep
401 path(length(path)) = [];
404 % If you have CStr2String, use the faster.
405 % path = CStr2String(C(R), dirsep, hasTrailFSep);
406 path = sprintf('%s\\', C{R});
408 path = [drive, path];
410 path = [drive, path(1:length(path) - 1)];
414 path = [drive, sprintf('%s/', C{R})];
416 path(length(path)) = [];
423 %%%% "Very
" long names under Windows.
429 + "The optional input argument `style` must be a
string or character-valued.
" + newline ...
433 if (strncmpi(style, 'a', 1) && length(path) >= MAX_PATH) || ...
434 strncmpi(style, 'f', 1)
435 % Do not use [isUNC] here, because this concerns the input, which can
436 % '.\path', while the current directory is an UNC path.
437 if strncmp(path, '\\', 2) % UNC path
438 path = ['\\?\UNC', path(2:end)];
440 path = ['\\?\', path];
function abs(in path, in style)
Return the Get absolute canonical path of a file or folder.