mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-01-31 11:37:35 +00:00
59b6ae1cbd
This also fixes some POSIX header warnings.
154 lines
6.7 KiB
C
154 lines
6.7 KiB
C
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
|
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
|
╞══════════════════════════════════════════════════════════════════════════════╡
|
|
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
|
│ │
|
|
│ Permission to use, copy, modify, and/or distribute this software for │
|
|
│ any purpose with or without fee is hereby granted, provided that the │
|
|
│ above copyright notice and this permission notice appear in all copies. │
|
|
│ │
|
|
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
|
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
|
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
|
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
|
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
|
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
|
#include "libc/dce.h"
|
|
#include "libc/str/path.h"
|
|
#include "libc/str/str.h"
|
|
|
|
/**
|
|
* Classifies file path name.
|
|
*
|
|
* For the purposes of this function, we always consider backslash
|
|
* interchangeable with forward slash, even though the underlying
|
|
* operating system might not. Therefore, for the sake of clarity,
|
|
* remaining documentation will only use the forward slash.
|
|
*
|
|
* This function behaves the same on all platforms. For instance, this
|
|
* function will categorize `C:/FOO.BAR` as a DOS path, even if you're
|
|
* running on UNIX rather than DOS.
|
|
*
|
|
* If you wish to check if a pathname is absolute, in a manner that's
|
|
* inclusive of DOS drive paths, DOS rooted paths, in addition to the
|
|
* New Technology UNC paths, then you may do the following:
|
|
*
|
|
* if (_classifypath(str) & _kPathAbs) { ... }
|
|
*
|
|
* To check if path is a relative path:
|
|
*
|
|
* if (~_classifypath(str) & _kPathAbs) { ... }
|
|
*
|
|
* Please note the above check includes rooted paths such as `\foo`
|
|
* which is considered absolute by MSDN and we consider it absolute
|
|
* although, it's technically relative to the current drive letter.
|
|
*
|
|
* Please note that `/foo/bar` is an absolute path on Windows, even
|
|
* though it's actually a rooted path that's considered relative to
|
|
* current drive by WIN32.
|
|
*
|
|
* @return integer value that's one of following:
|
|
* - `0` if non-weird relative path e.g. `c`
|
|
* - `_kPathAbs` if absolute (or rooted dos) path e.g. `/⋯`
|
|
* - `_kPathDos` if `c:`, `d:foo` i.e. drive-relative path
|
|
* - `_kPathAbs|_kPathDos` if proper dos path e.g. `c:/foo`
|
|
* - `_kPathDos|_kPathDev` if dos device path e.g. `nul`, `conin$`
|
|
* - `_kPathAbs|_kPathWin` if `//c`, `//?c`, etc.
|
|
* - `_kPathAbs|_kPathWin|_kPathDev` if `//./⋯`, `//?/⋯`
|
|
* - `_kPathAbs|_kPathWin|_kPathDev|_kPathRoot` if `//.` or `//?`
|
|
* - `_kPathAbs|_kPathNt` e.g. `\??\\⋯` (undoc. strict backslash)
|
|
* @see "The Definitive Guide on Win32 to NT Path Conversion", James
|
|
* Forshaw, Google Project Zero Blog, 2016-02-29
|
|
* @see "Naming Files, Paths, and Namespaces", MSDN 01/04/2021
|
|
*/
|
|
int _classifypath(const char *s) {
|
|
if (s) {
|
|
switch (s[0]) {
|
|
case 0: // ""
|
|
return 0;
|
|
default:
|
|
if (!SupportsWindows()) {
|
|
return 0;
|
|
}
|
|
if (((((s[0] == 'a' || s[0] == 'A') && // aux
|
|
(s[1] == 'u' || s[1] == 'U') && //
|
|
(s[2] == 'x' || s[2] == 'X')) || //
|
|
((s[0] == 'p' || s[0] == 'P') && // prn
|
|
(s[1] == 'r' || s[1] == 'R') && //
|
|
(s[2] == 'n' || s[2] == 'N')) || //
|
|
((s[0] == 'n' || s[0] == 'N') && // nul
|
|
(s[1] == 'u' || s[1] == 'U') && //
|
|
(s[2] == 'l' || s[2] == 'L')) || //
|
|
((s[0] == 'c' || s[0] == 'C') && // con
|
|
(s[1] == 'o' || s[1] == 'O') && //
|
|
(s[2] == 'n' || s[2] == 'N'))) && //
|
|
!s[3]) ||
|
|
((((s[0] == 'l' || s[0] == 'L') && // lpt
|
|
(s[1] == 'p' || s[1] == 'P') && //
|
|
(s[2] == 't' || s[2] == 'T')) || //
|
|
((s[0] == 'c' || s[0] == 'C') && // com
|
|
(s[1] == 'o' || s[1] == 'O') && //
|
|
(s[2] == 'm' || s[2] == 'M'))) && //
|
|
('1' <= s[3] && s[3] <= '9') && //
|
|
!s[4])) {
|
|
return _kPathDos | _kPathDev;
|
|
}
|
|
switch (s[1]) {
|
|
case ':':
|
|
switch (s[2]) {
|
|
case 0: // c:
|
|
default: // c:wut⋯
|
|
return _kPathDos;
|
|
case '/': // c:/⋯
|
|
case '\\': // c:\⋯
|
|
return _kPathAbs | _kPathDos;
|
|
}
|
|
default:
|
|
return 0;
|
|
}
|
|
case '\\':
|
|
if (SupportsWindows()) {
|
|
if (s[1] == '?' && s[2] == '?') {
|
|
if (!s[3]) {
|
|
return _kPathAbs | _kPathNt | _kPathRoot; // \??\⋯
|
|
} else if (s[3] == '\\') {
|
|
return _kPathAbs | _kPathNt; // \??\⋯
|
|
}
|
|
}
|
|
}
|
|
// fallthrough
|
|
case '/':
|
|
if (!SupportsWindows()) {
|
|
return _kPathAbs;
|
|
}
|
|
switch (s[1]) {
|
|
case 0: // /
|
|
default: // /⋯
|
|
return _kPathAbs;
|
|
case '/':
|
|
case '\\':
|
|
switch (s[2]) {
|
|
case 0: // //
|
|
default: // //⋯
|
|
return _kPathAbs | _kPathWin;
|
|
case '.':
|
|
case '?':
|
|
switch (s[3]) {
|
|
case 0: // //? or //.
|
|
return _kPathAbs | _kPathWin | _kPathDev | _kPathRoot;
|
|
default: // //?⋯ or //.⋯
|
|
return _kPathAbs | _kPathWin;
|
|
case '/':
|
|
case '\\': // //?/⋯ or //./⋯
|
|
return _kPathAbs | _kPathWin | _kPathDev;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|