mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-06-27 14:58:30 +00:00
Fix basename() and dirname()
This commit is contained in:
parent
9b11206ae3
commit
04d39d47f1
41 changed files with 489 additions and 207 deletions
|
@ -17,15 +17,23 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/nt/enum/filetype.h"
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
textwindows int64_t sys_lseek_nt(int fd, int64_t offset, int whence) {
|
||||
int64_t res;
|
||||
if (!__isfdkind(fd, kFdFile)) return ebadf();
|
||||
if (SetFilePointerEx(g_fds.p[fd].handle, offset, &res, whence)) {
|
||||
return res;
|
||||
if (__isfdkind(fd, kFdFile)) {
|
||||
if (GetFileType(g_fds.p[fd].handle) != kNtFileTypePipe) {
|
||||
if (SetFilePointerEx(g_fds.p[fd].handle, offset, &res, whence)) {
|
||||
return res;
|
||||
} else {
|
||||
return __winerr();
|
||||
}
|
||||
} else {
|
||||
return espipe();
|
||||
}
|
||||
} else {
|
||||
return __winerr();
|
||||
return ebadf();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,8 +53,8 @@
|
|||
|
||||
static textwindows int64_t sys_open_nt_impl(int dirfd, const char *path,
|
||||
uint32_t flags, int32_t mode) {
|
||||
uint32_t br;
|
||||
int64_t handle;
|
||||
uint32_t br, err;
|
||||
char16_t path16[PATH_MAX];
|
||||
uint32_t perm, share, disp, attr;
|
||||
if (__mkntpathat(dirfd, path, flags, path16) == -1) return -1;
|
||||
|
@ -96,6 +96,18 @@ static textwindows int64_t sys_open_nt_impl(int dirfd, const char *path,
|
|||
} else {
|
||||
attr = kNtFileAttributeNormal;
|
||||
if (flags & _O_DIRECTORY) attr |= kNtFileFlagBackupSemantics;
|
||||
if (~mode & 0200) {
|
||||
attr |= kNtFileAttributeReadonly;
|
||||
if (!IsTiny() && disp == kNtCreateAlways) {
|
||||
// iron out esoteric unix/win32 inconsistency (golang #38225)
|
||||
if ((handle = CreateFile(path16, perm, share, &kNtIsInheritable,
|
||||
kNtTruncateExisting, kNtFileAttributeNormal,
|
||||
0)) != -1 ||
|
||||
(errno != ENOENT && errno != ENOTDIR)) {
|
||||
return handle;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
flags |= kNtFileFlagOverlapped;
|
||||
if (~flags & _O_INDEXED) attr |= kNtFileAttributeNotContentIndexed;
|
||||
|
@ -105,14 +117,7 @@ static textwindows int64_t sys_open_nt_impl(int dirfd, const char *path,
|
|||
if (flags & _O_DIRECT) attr |= kNtFileFlagNoBuffering;
|
||||
if (flags & _O_NDELAY) attr |= kNtFileFlagWriteThrough;
|
||||
|
||||
if ((handle = CreateFile(path16, perm, share, &kNtIsInheritable, disp, attr,
|
||||
0)) != -1) {
|
||||
} else if (GetLastError() == kNtErrorFileExists &&
|
||||
((flags & _O_CREAT) &&
|
||||
(flags & _O_TRUNC))) { /* TODO(jart): What was this? */
|
||||
handle = eisdir();
|
||||
}
|
||||
return handle;
|
||||
return CreateFile(path16, perm, share, &kNtIsInheritable, disp, attr, 0);
|
||||
}
|
||||
|
||||
static textwindows ssize_t sys_open_nt_console(int dirfd,
|
||||
|
|
|
@ -21,13 +21,13 @@
|
|||
#include "libc/calls/internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/fmt/isslash.internal.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/nt/createfile.h"
|
||||
#include "libc/nt/enum/accessmask.h"
|
||||
#include "libc/nt/enum/creationdisposition.h"
|
||||
#include "libc/nt/enum/fileflagandattributes.h"
|
||||
#include "libc/nt/enum/filesharemode.h"
|
||||
#include "libc/str/path.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
|
@ -44,7 +44,7 @@ static void openanon_genpath(const char *name, struct OpenAnon *state,
|
|||
if (!name) name = "openanon";
|
||||
for (i = 0; p < pe; ++i) {
|
||||
if (!(c = name[i])) break;
|
||||
if (isslash(c)) c = '_';
|
||||
if (_isdirsep(c)) c = '_';
|
||||
*p++ = c;
|
||||
}
|
||||
*p++ = '.';
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "libc/mem/alloca.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/path.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/str/tpenc.h"
|
||||
#include "libc/str/utf16.h"
|
||||
|
|
|
@ -17,19 +17,42 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/fmt/isslash.internal.h"
|
||||
#include "libc/str/path.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
/**
|
||||
* Returns pointer to last filename component in path.
|
||||
* Returns pointer to last filename component in path, e.g.
|
||||
*
|
||||
* path │ dirname() │ basename()
|
||||
* ─────────────────────────────────
|
||||
* . │ . │ .
|
||||
* .. │ . │ ..
|
||||
* / │ / │ /
|
||||
* usr │ . │ usr
|
||||
* /usr/ │ / │ usr
|
||||
* /usr/lib │ /usr │ lib
|
||||
*
|
||||
* Both / and \ are are considered valid component separators on all
|
||||
* platforms. Trailing slashes are ignored. We don't grant special
|
||||
* consideration to things like foo/., c:/, \\?\Volume, etc.
|
||||
*
|
||||
* @param path is NUL-terminated UTF-8 path
|
||||
* @return pointer inside path or path itself
|
||||
* @param path is UTF-8 and may be mutated, but not expanded in length
|
||||
* @return pointer to path, or inside path, or to a special r/o string
|
||||
* @see dirname()
|
||||
* @see SUSv2
|
||||
*/
|
||||
textstartup char *basename(const char *path) {
|
||||
return basename_n(path, strlen(path));
|
||||
char *basename(char *path) {
|
||||
size_t i;
|
||||
if (path && *path) {
|
||||
i = strlen(path) - 1;
|
||||
for (; i && _isdirsep(path[i]); i--) {
|
||||
path[i] = 0;
|
||||
}
|
||||
for (; i && !_isdirsep(path[i - 1]);) {
|
||||
i--;
|
||||
}
|
||||
return path + i;
|
||||
} else {
|
||||
return ".";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,49 +0,0 @@
|
|||
/*-*- 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 2020 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/fmt/conv.h"
|
||||
#include "libc/fmt/isslash.internal.h"
|
||||
|
||||
/**
|
||||
* Returns pointer to last filename component in path.
|
||||
*
|
||||
* Both / and \ are are considered valid component separators on all
|
||||
* platforms. Trailing slashes are ignored. We don't grant special
|
||||
* consideration to things like foo/., c:/, \\?\Volume, etc.
|
||||
*
|
||||
* @param path is UTF-8 path
|
||||
* @param size is byte length of path
|
||||
* @return pointer inside path or path itself
|
||||
*/
|
||||
textstartup char *basename_n(const char *path, size_t size) {
|
||||
size_t i, l;
|
||||
if (size) {
|
||||
if (isslash(path[size - 1])) {
|
||||
l = size - 1;
|
||||
while (l && isslash(path[l - 1])) --l;
|
||||
if (!l) return (/*unconst*/ char *)&path[size - 1];
|
||||
size = l;
|
||||
}
|
||||
for (i = size; i > 0; --i) {
|
||||
if (isslash(path[i - 1])) {
|
||||
return (/*unconst*/ char *)&path[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
return (/*unconst*/ char *)path;
|
||||
}
|
|
@ -42,13 +42,13 @@ size_t wcsxfrm(wchar_t *, const wchar_t *, size_t);
|
|||
│ cosmopolitan § conversion » time ─╬─│┼
|
||||
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||
|
||||
int64_t DosDateTimeToUnix(unsigned, unsigned) dontthrow;
|
||||
struct timeval WindowsTimeToTimeVal(int64_t) dontthrow;
|
||||
struct timespec WindowsTimeToTimeSpec(int64_t) dontthrow;
|
||||
int64_t TimeSpecToWindowsTime(struct timespec) dontthrow;
|
||||
int64_t TimeValToWindowsTime(struct timeval) dontthrow;
|
||||
struct timeval WindowsDurationToTimeVal(int64_t) dontthrow;
|
||||
struct timespec WindowsDurationToTimeSpec(int64_t) dontthrow;
|
||||
int64_t DosDateTimeToUnix(unsigned, unsigned) libcesque nosideeffect;
|
||||
struct timeval WindowsTimeToTimeVal(int64_t) libcesque nosideeffect;
|
||||
struct timespec WindowsTimeToTimeSpec(int64_t) libcesque nosideeffect;
|
||||
int64_t TimeSpecToWindowsTime(struct timespec) libcesque nosideeffect;
|
||||
int64_t TimeValToWindowsTime(struct timeval) libcesque nosideeffect;
|
||||
struct timeval WindowsDurationToTimeVal(int64_t) libcesque nosideeffect;
|
||||
struct timespec WindowsDurationToTimeSpec(int64_t) libcesque nosideeffect;
|
||||
|
||||
static inline struct NtFileTime MakeFileTime(int64_t x) {
|
||||
return (struct NtFileTime){(uint32_t)x, (uint32_t)(x >> 32)};
|
||||
|
@ -69,9 +69,7 @@ static inline int64_t ReadFileTime(struct NtFileTime t) {
|
|||
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||
|
||||
char *dirname(char *);
|
||||
char *basename(const char *) nosideeffect;
|
||||
char *basename_n(const char *, size_t) nosideeffect;
|
||||
bool isabspath(const char *) paramsnonnull() nosideeffect;
|
||||
char *basename(char *);
|
||||
char *stripext(char *);
|
||||
char *stripexts(char *);
|
||||
|
||||
|
|
|
@ -17,34 +17,42 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/str/path.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
#define ISSLASH(c) (c == '/' || c == '\\')
|
||||
#define ISDELIM(c) (ISSLASH(c) || c == '.')
|
||||
|
||||
/**
|
||||
* Returns directory portion of path.
|
||||
* Returns directory portion of path, e.g.
|
||||
*
|
||||
* This returns "." if path doesn't have slashes. If path is empty then
|
||||
* this returns empty string.
|
||||
* path │ dirname() │ basename()
|
||||
* ─────────────────────────────────
|
||||
* . │ . │ .
|
||||
* .. │ . │ ..
|
||||
* / │ / │ /
|
||||
* usr │ . │ usr
|
||||
* /usr/ │ / │ usr
|
||||
* /usr/lib │ /usr │ lib
|
||||
*
|
||||
* @param s is mutated and must not be NULL
|
||||
* @param path is UTF-8 and may be mutated, but not expanded in length
|
||||
* @return pointer to path, or inside path, or to a special r/o string
|
||||
* @see basename()
|
||||
* @see SUSv2
|
||||
*/
|
||||
char *dirname(char *s) {
|
||||
size_t i, n;
|
||||
if (!(n = strlen(s))) return s;
|
||||
while (n && ISDELIM(s[n - 1])) --n;
|
||||
if (n) {
|
||||
while (n && !ISSLASH(s[n - 1])) --n;
|
||||
if (n) {
|
||||
while (n && ISDELIM(s[n - 1])) --n;
|
||||
if (!n) ++n;
|
||||
} else {
|
||||
s[n++] = '.';
|
||||
char *dirname(char *path) {
|
||||
size_t i;
|
||||
if (path && *path) {
|
||||
i = strlen(path) - 1;
|
||||
for (; _isdirsep(path[i]); i--) {
|
||||
if (!i) return "/";
|
||||
}
|
||||
for (; !_isdirsep(path[i]); i--) {
|
||||
if (!i) return ".";
|
||||
}
|
||||
for (; _isdirsep(path[i]); i--) {
|
||||
if (!i) return "/";
|
||||
}
|
||||
path[i + 1] = 0;
|
||||
return path;
|
||||
} else {
|
||||
++n;
|
||||
return ".";
|
||||
}
|
||||
s[n] = '\0';
|
||||
return s;
|
||||
}
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_FMT_ISSLASH_H_
|
||||
#define COSMOPOLITAN_LIBC_FMT_ISSLASH_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
|
||||
forceinline bool isslash(int c) {
|
||||
return c == '/' || c == '\\';
|
||||
}
|
||||
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_FMT_ISSLASH_H_ */
|
|
@ -36,6 +36,7 @@ kDos2Errno:
|
|||
.e kNtErrorBadNetName,ENOENT
|
||||
.e kNtErrorBadNetResp,ENETDOWN
|
||||
.e kNtErrorBadPathname,ENOENT
|
||||
.e kNtErrorFileExists,EEXIST
|
||||
.e kNtErrorCannotMake,EACCES
|
||||
.e kNtErrorCommitmentLimit,ENOMEM
|
||||
.e kNtErrorConnectionAborted,ECONNABORTED
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "libc/calls/calls.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/path.h"
|
||||
|
||||
/**
|
||||
* Returns current working directory.
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
*
|
||||
* This function is similar to getline() except it'll truncate lines
|
||||
* exceeding size. The line ending marker is included and may be removed
|
||||
* using chomp().
|
||||
* using _chomp().
|
||||
*/
|
||||
char *fgets(char *s, int size, FILE *f) {
|
||||
int c;
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
* @return number of bytes read >0, including delim, excluding NUL,
|
||||
* or -1 w/ errno on EOF or error; see ferror() and feof()
|
||||
* @note this function can't punt EINTR to caller
|
||||
* @see getline(), chomp(), gettok_r()
|
||||
* @see getline(), _chomp(), gettok_r()
|
||||
*/
|
||||
ssize_t getdelim(char **s, size_t *n, int delim, FILE *f) {
|
||||
char *p;
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
*
|
||||
* This function delegates to getdelim(), which provides further
|
||||
* documentation. Concerning lines, please note the \n or \r\n are
|
||||
* included in results, and can be removed with chomp().
|
||||
* included in results, and can be removed with _chomp().
|
||||
*
|
||||
* @param line is the caller's buffer (in/out) which is extended
|
||||
* automatically. *line may be NULL but only if *n is 0;
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
* @param line is NULL-propagating
|
||||
* @see getline
|
||||
*/
|
||||
char *chomp(char *line) {
|
||||
char *_chomp(char *line) {
|
||||
size_t i;
|
||||
if (line) {
|
||||
for (i = strlen(line); i--;) {
|
||||
|
|
|
@ -24,7 +24,16 @@
|
|||
* @param line is NULL-propagating
|
||||
* @see getline
|
||||
*/
|
||||
char16_t *chomp16(char16_t *line) {
|
||||
if (line) line[strcspn16(line, u"\r\n")] = '\0';
|
||||
char16_t *_chomp16(char16_t *line) {
|
||||
size_t i;
|
||||
if (line) {
|
||||
for (i = strlen16(line); i--;) {
|
||||
if (line[i] == '\r' || line[i] == '\n') {
|
||||
line[i] = '\0';
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return line;
|
||||
}
|
||||
|
|
154
libc/str/classifypath.c
Normal file
154
libc/str/classifypath.c
Normal file
|
@ -0,0 +1,154 @@
|
|||
/*-*- 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) & _PATH_ABS) { ... }
|
||||
*
|
||||
* To check if path is a relative path:
|
||||
*
|
||||
* if (~_classifypath(str) & _PATH_ABS) { ... }
|
||||
*
|
||||
* 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`
|
||||
* - `_PATH_ABS` if absolute (or rooted dos) path e.g. `/⋯`
|
||||
* - `_PATH_DOS` if `c:`, `d:foo` i.e. drive-relative path
|
||||
* - `_PATH_ABS|_PATH_DOS` if proper dos path e.g. `c:/foo`
|
||||
* - `_PATH_DOS|_PATH_DEV` if dos device path e.g. `nul`, `conin$`
|
||||
* - `_PATH_ABS|_PATH_WIN` if `//c`, `//?c`, etc.
|
||||
* - `_PATH_ABS|_PATH_WIN|_PATH_DEV` if `//./⋯`, `//?/⋯`
|
||||
* - `_PATH_ABS|_PATH_WIN|_PATH_DEV|_PATH_ROOT` if `//.` or `//?`
|
||||
* - `_PATH_ABS|_PATH_NT` 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 _PATH_DOS | _PATH_DEV;
|
||||
}
|
||||
switch (s[1]) {
|
||||
case ':':
|
||||
switch (s[2]) {
|
||||
case 0: // c:
|
||||
default: // c:wut⋯
|
||||
return _PATH_DOS;
|
||||
case '/': // c:/⋯
|
||||
case '\\': // c:\⋯
|
||||
return _PATH_ABS | _PATH_DOS;
|
||||
}
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
case '\\':
|
||||
if (SupportsWindows()) {
|
||||
if (s[1] == '?' && s[2] == '?') {
|
||||
if (!s[3]) {
|
||||
return _PATH_ABS | _PATH_NT | _PATH_ROOT; // \??\⋯
|
||||
} else if (s[3] == '\\') {
|
||||
return _PATH_ABS | _PATH_NT; // \??\⋯
|
||||
}
|
||||
}
|
||||
}
|
||||
// fallthrough
|
||||
case '/':
|
||||
if (!SupportsWindows()) {
|
||||
return _PATH_ABS;
|
||||
}
|
||||
switch (s[1]) {
|
||||
case 0: // /
|
||||
default: // /⋯
|
||||
return _PATH_ABS;
|
||||
case '/':
|
||||
case '\\':
|
||||
switch (s[2]) {
|
||||
case 0: // //
|
||||
default: // //⋯
|
||||
return _PATH_ABS | _PATH_WIN;
|
||||
case '.':
|
||||
case '?':
|
||||
switch (s[3]) {
|
||||
case 0: // //? or //.
|
||||
return _PATH_ABS | _PATH_WIN | _PATH_DEV | _PATH_ROOT;
|
||||
default: // //?⋯ or //.⋯
|
||||
return _PATH_ABS | _PATH_WIN;
|
||||
case '/':
|
||||
case '\\': // //?/⋯ or //./⋯
|
||||
return _PATH_ABS | _PATH_WIN | _PATH_DEV;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
|
@ -43,8 +43,8 @@ static textwindows bool shouldquotedos(const char16_t c) {
|
|||
* Escapes command so DOS can run it.
|
||||
* @see Iain Patterson's NSSM for original code in public domain
|
||||
*/
|
||||
textwindows bool escapedos(char16_t *buffer, unsigned buflen,
|
||||
const char16_t *unquoted, unsigned len) {
|
||||
textwindows bool _escapedos(char16_t *buffer, unsigned buflen,
|
||||
const char16_t *unquoted, unsigned len) {
|
||||
unsigned i, j, n;
|
||||
if (len > buflen - 1) return false;
|
||||
bool escape = false;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*-*- 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 2021 Justine Alexandra Roberts Tunney │
|
||||
│ Copyright 2020 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 │
|
||||
|
@ -16,33 +16,21 @@
|
|||
│ 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"
|
||||
|
||||
/**
|
||||
* Returns true if pathname is absolute, e.g.
|
||||
* Returns true if pathname is considered absolute.
|
||||
*
|
||||
* - `/home/jart/foo.txt` is absolute
|
||||
* - `C:/Users/jart/foo.txt` is absolute on NT
|
||||
* - `C:\Users\jart\foo.txt` is absolute on NT
|
||||
* - `\??\C:\Users\jart\foo.txt` is absolute on NT
|
||||
* - `\\.\C:\Users\jart\foo.txt` is absolute on NT
|
||||
* - `/Users/jart/foo.txt` we consider it absolute enough on NT
|
||||
* - `\Users\jart\foo.txt` we consider it absolute enough on NT
|
||||
* - `C:/Users/jart/foo.txt` is absolute on Windows
|
||||
* - `C:\Users\jart\foo.txt` is absolute on Windows
|
||||
* - `\??\C:\Users\jart\foo.txt` is absolute on Windows
|
||||
* - `\\.\C:\Users\jart\foo.txt` is absolute on Windows
|
||||
* - `/Users/jart/foo.txt` is effectively absolute on Windows
|
||||
* - `\Users\jart\foo.txt` is effectively absolute on Windows
|
||||
*
|
||||
* Please note that the recommended approach to using Cosmopolitan is to
|
||||
* not use absolute paths at all. If you do use absolute paths then it's
|
||||
* a good idea on Windows to stay within the C: drive. This is because
|
||||
* Cosmopolitan Libc doesn't create a virtual filesystem layer and
|
||||
* instead just replaces `\` characters with `/`.
|
||||
*/
|
||||
bool _isabspath(const char *p) {
|
||||
if (*p == '/') {
|
||||
return true;
|
||||
}
|
||||
if (IsWindows() &&
|
||||
(*p == '/' || *p == '\\' || (isalpha(p[0]) && p[1] == ':'))) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
bool _isabspath(const char *path) {
|
||||
return _classifypath(path) & _PATH_ABS;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*-*- 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 2020 Justine Alexandra Roberts Tunney │
|
||||
│ 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 │
|
||||
|
@ -16,23 +16,12 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/fmt/isslash.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
/**
|
||||
* Returns true if pathname could be absolute on any known platform.
|
||||
*
|
||||
* The ones we know about are System V (/foo/bar), DOS (C:\foo\bar),
|
||||
* Windows NT (\\.\C:\foo\bar), Google Cloud (gs://bucket/foo/bar), etc.
|
||||
* Returns true if character is directory separator slash.
|
||||
*/
|
||||
bool isabspath(const char *path) {
|
||||
if (isslash(*path)) return true;
|
||||
for (; *path; ++path) {
|
||||
if (isslash(*path)) return false;
|
||||
if (*path == ':') {
|
||||
++path;
|
||||
if (isslash(*path)) return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
bool _isdirsep(int c) {
|
||||
return c == '/' || c == '\\';
|
||||
}
|
20
libc/str/path.h
Normal file
20
libc/str/path.h
Normal file
|
@ -0,0 +1,20 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_STR_PATH_H_
|
||||
#define COSMOPOLITAN_LIBC_STR_PATH_H_
|
||||
|
||||
#define _PATH_ABS 1
|
||||
#define _PATH_DEV 2
|
||||
#define _PATH_ROOT 4
|
||||
#define _PATH_DOS 8
|
||||
#define _PATH_WIN 16
|
||||
#define _PATH_NT 32
|
||||
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
int _classifypath(const char *) libcesque nosideeffect;
|
||||
bool _isabspath(const char *) libcesque strlenesque;
|
||||
bool _isdirsep(int) libcesque pureconst;
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_STR_PATH_H_ */
|
|
@ -196,17 +196,16 @@ char *strerror(int) returnsnonnull dontthrow nocallback;
|
|||
long a64l(const char *);
|
||||
char *l64a(long);
|
||||
|
||||
char *strntolower(char *, size_t);
|
||||
char *strtolower(char *) paramsnonnull();
|
||||
char *strntoupper(char *, size_t);
|
||||
char *strtoupper(char *) paramsnonnull();
|
||||
char *chomp(char *);
|
||||
char16_t *chomp16(char16_t *);
|
||||
wchar_t *wchomp(wchar_t *);
|
||||
bool _istext(const void *, size_t);
|
||||
bool _isutf8(const void *, size_t);
|
||||
bool _isabspath(const char *) strlenesque;
|
||||
bool escapedos(char16_t *, unsigned, const char16_t *, unsigned);
|
||||
char *strntolower(char *, size_t) libcesque;
|
||||
char *strtolower(char *) libcesque paramsnonnull();
|
||||
char *strntoupper(char *, size_t) libcesque;
|
||||
char *strtoupper(char *) libcesque paramsnonnull();
|
||||
char *_chomp(char *) libcesque;
|
||||
char16_t *_chomp16(char16_t *) libcesque;
|
||||
wchar_t *_wchomp(wchar_t *) libcesque;
|
||||
bool _istext(const void *, size_t) libcesque;
|
||||
bool _isutf8(const void *, size_t) libcesque;
|
||||
bool _escapedos(char16_t *, unsigned, const char16_t *, unsigned) libcesque;
|
||||
|
||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||
│ cosmopolitan § strings » multibyte ─╬─│┼
|
||||
|
|
|
@ -24,7 +24,16 @@
|
|||
* @param line is NULL-propagating
|
||||
* @see getline
|
||||
*/
|
||||
wchar_t *wchomp(wchar_t *line) {
|
||||
if (line) line[wcscspn(line, L"\r\n")] = '\0';
|
||||
wchar_t *_wchomp(wchar_t *line) {
|
||||
size_t i;
|
||||
if (line) {
|
||||
for (i = wcslen(line); i--;) {
|
||||
if (line[i] == '\r' || line[i] == '\n') {
|
||||
line[i] = '\0';
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return line;
|
||||
}
|
||||
|
|
|
@ -17,11 +17,12 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/runtime/gc.internal.h"
|
||||
#include "libc/x/x.h"
|
||||
|
||||
/**
|
||||
* Returns directory portion of path.
|
||||
*/
|
||||
char *xdirname(const char *path) {
|
||||
return dirname(xstrdup(path));
|
||||
return xstrdup(dirname(gc(xstrdup(path))));
|
||||
}
|
||||
|
|
|
@ -23,10 +23,10 @@
|
|||
/**
|
||||
* Reads line from stream.
|
||||
*
|
||||
* @return allocated line that needs free() and usually chomp() too,
|
||||
* @return allocated line that needs free() and usually _chomp() too,
|
||||
* or NULL on ferror() or feof()
|
||||
* @see getdelim() for a more difficult api
|
||||
* @see chomp()
|
||||
* @see _chomp()
|
||||
*/
|
||||
char *xgetline(FILE *f) {
|
||||
char *p;
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/safemacros.internal.h"
|
||||
#include "libc/str/path.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/x/x.h"
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue