mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-01-31 03:27:39 +00:00
Fix basename() and dirname()
This commit is contained in:
parent
9b11206ae3
commit
04d39d47f1
41 changed files with 489 additions and 207 deletions
|
@ -121,7 +121,7 @@ void SpellChecker(void) {
|
|||
printf("word: ");
|
||||
fflush(stdout);
|
||||
if (getline(&line, &linesize, stdin) > 0) {
|
||||
query = strtolower(chomp(line));
|
||||
query = strtolower(_chomp(line));
|
||||
if (critbit0_contains(&words, query)) {
|
||||
printf("ok\r\n");
|
||||
} else {
|
||||
|
@ -147,7 +147,7 @@ void SpellChecker(void) {
|
|||
void LoadWords(void) {
|
||||
CHECK_NOTNULL((f = fopen("/zip/usr/share/dict/words", "r")));
|
||||
while (getline(&line, &linesize, f) > 0) {
|
||||
critbit0_insert(&words, strtolower(chomp(line)));
|
||||
critbit0_insert(&words, strtolower(_chomp(line)));
|
||||
}
|
||||
CHECK_NE(-1, fclose(f));
|
||||
}
|
||||
|
|
|
@ -1673,7 +1673,7 @@ char* GetLine(void) {
|
|||
static char* line;
|
||||
static size_t linesize;
|
||||
if (getline(&line, &linesize, stdin) > 0) {
|
||||
return chomp(line);
|
||||
return _chomp(line);
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ void LogCertificate(const char *msg, mbedtls_x509_crt *cert) {
|
|||
if (LOGGABLE(kLogDebug)) {
|
||||
if ((s = malloc((n = 15000)))) {
|
||||
if (mbedtls_x509_crt_info(s, n, " ", cert) > 0) {
|
||||
DEBUGF("%s\n%s", msg, chomp(s));
|
||||
DEBUGF("%s\n%s", msg, _chomp(s));
|
||||
}
|
||||
free(s);
|
||||
}
|
||||
|
|
|
@ -54,9 +54,9 @@ TEST(mkdir, testPathIsDirectory_EEXIST) {
|
|||
EXPECT_EQ(EEXIST, errno);
|
||||
}
|
||||
|
||||
TEST(makedirs, testEmptyString_ENOENT) {
|
||||
TEST(makedirs, testEmptyString_EEXIST) {
|
||||
EXPECT_EQ(-1, makedirs("", 0755));
|
||||
EXPECT_EQ(ENOENT, errno);
|
||||
EXPECT_EQ(EEXIST, errno);
|
||||
}
|
||||
|
||||
TEST(mkdirat, testRelativePath_opensRelativeToDirFd) {
|
||||
|
|
|
@ -21,25 +21,33 @@
|
|||
#include "libc/mem/mem.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
|
||||
TEST(basename, test) {
|
||||
EXPECT_STREQ("", basename(""));
|
||||
EXPECT_STREQ("/", basename("/"));
|
||||
EXPECT_STREQ("hello", basename("hello"));
|
||||
EXPECT_STREQ("there", basename("hello/there"));
|
||||
EXPECT_STREQ("yo", basename("hello/there/yo"));
|
||||
#define BASENAME(x) basename(gc(strdup(x)))
|
||||
|
||||
TEST(basename, testRegularExamples) {
|
||||
EXPECT_STREQ("lib", BASENAME("/usr/lib"));
|
||||
EXPECT_STREQ("lib", BASENAME("usr/lib"));
|
||||
EXPECT_STREQ("usr", BASENAME("/usr/"));
|
||||
EXPECT_STREQ("usr", BASENAME("usr"));
|
||||
EXPECT_STREQ("/", BASENAME("/"));
|
||||
EXPECT_STREQ(".", BASENAME("."));
|
||||
EXPECT_STREQ("..", BASENAME(".."));
|
||||
}
|
||||
|
||||
TEST(basename, testIrregularExamples) {
|
||||
EXPECT_STREQ(".", basename(0));
|
||||
EXPECT_STREQ(".", basename(""));
|
||||
}
|
||||
|
||||
TEST(basename, testTrailingSlash_isIgnored) {
|
||||
/* should be "foo" but basename() doesn't allocate memory */
|
||||
EXPECT_STREQ("foo/", basename("foo/"));
|
||||
EXPECT_STREQ("foo//", basename("foo//"));
|
||||
EXPECT_STREQ("foo", BASENAME("foo/"));
|
||||
EXPECT_STREQ("foo", BASENAME("foo//"));
|
||||
}
|
||||
|
||||
TEST(basename, testOnlySlashes_oneSlashOnlyVasily) {
|
||||
EXPECT_STREQ("/", basename("///"));
|
||||
EXPECT_STREQ("/", BASENAME("///"));
|
||||
}
|
||||
|
||||
TEST(basename, testWindows_isGrantedRespect) {
|
||||
EXPECT_STREQ("there", basename("hello\\there"));
|
||||
EXPECT_STREQ("yo", basename("hello\\there\\yo"));
|
||||
EXPECT_STREQ("there", BASENAME("hello\\there"));
|
||||
EXPECT_STREQ("yo", BASENAME("hello\\there\\yo"));
|
||||
}
|
||||
|
|
|
@ -26,12 +26,11 @@
|
|||
TEST(dirname, test) {
|
||||
EXPECT_STREQ("/usr/lib", dirname(gc(strdup("/usr/lib/foo.bar"))));
|
||||
EXPECT_STREQ("/usr", dirname(gc(strdup("/usr/lib"))));
|
||||
EXPECT_STREQ("/usr", dirname(gc(strdup("/usr/lib"))));
|
||||
EXPECT_STREQ("usr", dirname(gc(strdup("usr/lib"))));
|
||||
EXPECT_STREQ("/", dirname(gc(strdup("/usr/"))));
|
||||
EXPECT_STREQ(".", dirname(gc(strdup("usr"))));
|
||||
EXPECT_STREQ("/", dirname(gc(strdup("/"))));
|
||||
EXPECT_STREQ(".", dirname(gc(strdup("hello"))));
|
||||
EXPECT_STREQ(".", dirname(gc(strdup("."))));
|
||||
EXPECT_STREQ(".", dirname(gc(strdup(".."))));
|
||||
EXPECT_STREQ("", dirname(gc(strdup(""))));
|
||||
EXPECT_STREQ(".", dirname(gc(strdup(""))));
|
||||
}
|
||||
|
|
116
test/libc/str/classifypath_test.c
Normal file
116
test/libc/str/classifypath_test.c
Normal file
|
@ -0,0 +1,116 @@
|
|||
/*-*- 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/str/path.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
|
||||
TEST(isabspath, testUniversal) {
|
||||
ASSERT_TRUE(_isabspath("/home/jart/foo.txt"));
|
||||
}
|
||||
|
||||
TEST(isabspath, testDosPaths) {
|
||||
ASSERT_FALSE(_isabspath("C:"));
|
||||
ASSERT_FALSE(_isabspath("C:foo.txt"));
|
||||
ASSERT_TRUE(_isabspath("C:/"));
|
||||
ASSERT_TRUE(_isabspath("C:/Users/jart/foo.txt"));
|
||||
ASSERT_TRUE(_isabspath("C:\\Users\\jart\\foo.txt"));
|
||||
ASSERT_TRUE(_isabspath("\\Users\\jart\\foo.txt"));
|
||||
}
|
||||
|
||||
TEST(isabspath, testWin32Paths) {
|
||||
ASSERT_TRUE(_isabspath("\\\\?\\C:\\.."));
|
||||
ASSERT_TRUE(_isabspath("\\\\.\\C:\\Users\\jart\\foo.txt"));
|
||||
}
|
||||
|
||||
TEST(isabspath, testNtPaths) {
|
||||
ASSERT_TRUE(_isabspath("\\??\\C:\\Users\\jart\\foo.txt"));
|
||||
}
|
||||
|
||||
TEST(_classifypath, test) {
|
||||
EXPECT_EQ(0, _classifypath(""));
|
||||
EXPECT_EQ(0, _classifypath("xyz"));
|
||||
EXPECT_EQ(_PATH_DOS | _PATH_DEV, _classifypath("CON"));
|
||||
EXPECT_EQ(_PATH_DOS | _PATH_DEV, _classifypath("NUL"));
|
||||
EXPECT_EQ(0, _classifypath(":"));
|
||||
EXPECT_EQ(_PATH_DOS, _classifypath("::"));
|
||||
EXPECT_EQ(_PATH_DOS, _classifypath(":::"));
|
||||
EXPECT_EQ(_PATH_DOS, _classifypath("::::"));
|
||||
EXPECT_EQ(_PATH_ABS | _PATH_DOS, _classifypath("::\\"));
|
||||
EXPECT_EQ(_PATH_ABS, _classifypath("\\"));
|
||||
EXPECT_EQ(_PATH_ABS, _classifypath("\\:"));
|
||||
EXPECT_EQ(_PATH_ABS, _classifypath("\\C:"));
|
||||
EXPECT_EQ(_PATH_ABS, _classifypath("\\C:\\"));
|
||||
EXPECT_EQ(_PATH_ABS, _classifypath("/"));
|
||||
EXPECT_EQ(_PATH_ABS, _classifypath("/:"));
|
||||
EXPECT_EQ(_PATH_ABS, _classifypath("/C:"));
|
||||
EXPECT_EQ(_PATH_ABS, _classifypath("/C:/"));
|
||||
EXPECT_EQ(0, _classifypath("C"));
|
||||
EXPECT_EQ(_PATH_DOS, _classifypath("C:"));
|
||||
EXPECT_EQ(_PATH_DOS, _classifypath("C:a"));
|
||||
EXPECT_EQ(_PATH_DOS, _classifypath("C:a\\"));
|
||||
EXPECT_EQ(_PATH_ABS | _PATH_DOS, _classifypath("C:\\"));
|
||||
EXPECT_EQ(_PATH_ABS | _PATH_DOS, _classifypath("C:/"));
|
||||
EXPECT_EQ(_PATH_ABS | _PATH_DOS, _classifypath("C:\\a"));
|
||||
EXPECT_EQ(_PATH_ABS | _PATH_DOS, _classifypath("C:/a"));
|
||||
EXPECT_EQ(_PATH_ABS | _PATH_DOS, _classifypath("C:\\\\"));
|
||||
EXPECT_EQ(_PATH_ABS | _PATH_WIN, _classifypath("\\\\"));
|
||||
EXPECT_EQ(_PATH_ABS | _PATH_WIN, _classifypath("\\\\\\"));
|
||||
EXPECT_EQ(_PATH_ABS | _PATH_WIN, _classifypath("\\\\;"));
|
||||
EXPECT_EQ(_PATH_ABS | _PATH_WIN, _classifypath("\\\\f\\b\\"));
|
||||
EXPECT_EQ(_PATH_ABS | _PATH_WIN, _classifypath("\\\\f\\b"));
|
||||
EXPECT_EQ(_PATH_ABS | _PATH_WIN, _classifypath("\\\\f\\"));
|
||||
EXPECT_EQ(_PATH_ABS | _PATH_WIN, _classifypath("\\\\f"));
|
||||
EXPECT_EQ(_PATH_ABS | _PATH_NT, _classifypath("\\??\\"));
|
||||
EXPECT_EQ(_PATH_ABS | _PATH_NT, _classifypath("\\??\\UNC"));
|
||||
EXPECT_EQ(_PATH_ABS | _PATH_NT, _classifypath("\\??\\UNC\\"));
|
||||
EXPECT_EQ(_PATH_ABS, _classifypath("\\?"));
|
||||
EXPECT_EQ(_PATH_ABS, _classifypath("\\?\\"));
|
||||
EXPECT_EQ(_PATH_ABS, _classifypath("\\?\\UNC"));
|
||||
EXPECT_EQ(_PATH_ABS, _classifypath("\\?\\UNC\\"));
|
||||
EXPECT_EQ(_PATH_ABS | _PATH_WIN | _PATH_DEV, _classifypath("\\\\?\\UNC\\"));
|
||||
EXPECT_EQ(_PATH_ABS | _PATH_WIN | _PATH_DEV | _PATH_ROOT,
|
||||
_classifypath("\\\\?"));
|
||||
EXPECT_EQ(_PATH_ABS | _PATH_WIN, _classifypath("\\\\??"));
|
||||
EXPECT_EQ(_PATH_ABS | _PATH_WIN, _classifypath("\\\\??\\"));
|
||||
EXPECT_EQ(_PATH_ABS | _PATH_WIN, _classifypath("\\\\??\\C:\\"));
|
||||
EXPECT_EQ(_PATH_ABS | _PATH_WIN | _PATH_DEV | _PATH_ROOT,
|
||||
_classifypath("\\\\."));
|
||||
EXPECT_EQ(_PATH_ABS | _PATH_WIN | _PATH_DEV, _classifypath("\\\\.\\"));
|
||||
EXPECT_EQ(_PATH_ABS | _PATH_WIN | _PATH_DEV, _classifypath("\\\\.\\C:\\"));
|
||||
EXPECT_EQ(_PATH_ABS | _PATH_WIN, _classifypath("\\/"));
|
||||
EXPECT_EQ(_PATH_ABS | _PATH_WIN, _classifypath("/\\"));
|
||||
EXPECT_EQ(_PATH_ABS | _PATH_WIN, _classifypath("//"));
|
||||
EXPECT_EQ(_PATH_ABS | _PATH_WIN, _classifypath("///"));
|
||||
EXPECT_EQ(_PATH_ABS | _PATH_WIN, _classifypath("//;"));
|
||||
EXPECT_EQ(_PATH_ABS | _PATH_WIN | _PATH_DEV | _PATH_ROOT,
|
||||
_classifypath("//?"));
|
||||
EXPECT_EQ(_PATH_ABS | _PATH_WIN | _PATH_DEV | _PATH_ROOT,
|
||||
_classifypath("/\\?"));
|
||||
EXPECT_EQ(_PATH_ABS | _PATH_WIN | _PATH_DEV | _PATH_ROOT,
|
||||
_classifypath("\\/?"));
|
||||
EXPECT_EQ(_PATH_ABS | _PATH_WIN, _classifypath("//??"));
|
||||
EXPECT_EQ(_PATH_ABS | _PATH_WIN | _PATH_DEV | _PATH_ROOT,
|
||||
_classifypath("//."));
|
||||
EXPECT_EQ(_PATH_ABS | _PATH_WIN | _PATH_DEV | _PATH_ROOT,
|
||||
_classifypath("\\/."));
|
||||
EXPECT_EQ(_PATH_ABS | _PATH_WIN | _PATH_DEV | _PATH_ROOT,
|
||||
_classifypath("/\\."));
|
||||
EXPECT_EQ(_PATH_ABS | _PATH_WIN | _PATH_DEV, _classifypath("//./"));
|
||||
EXPECT_EQ(_PATH_ABS | _PATH_WIN | _PATH_DEV, _classifypath("//./C:/"));
|
||||
}
|
10
third_party/quickjs/quickjs-libc.c
vendored
10
third_party/quickjs/quickjs-libc.c
vendored
|
@ -3063,7 +3063,7 @@ typedef struct {
|
|||
|
||||
typedef struct {
|
||||
char *filename; /* module filename */
|
||||
char *basename; /* module base name */
|
||||
char *basename_; /* module base name */
|
||||
JSWorkerMessagePipe *recv_pipe, *send_pipe;
|
||||
} WorkerFuncArgs;
|
||||
|
||||
|
@ -3231,10 +3231,10 @@ static void *worker_func(void *opaque)
|
|||
|
||||
js_std_add_helpers(ctx, -1, NULL);
|
||||
|
||||
if (!JS_RunModule(ctx, args->basename, args->filename))
|
||||
if (!JS_RunModule(ctx, args->basename_, args->filename))
|
||||
js_std_dump_error(ctx);
|
||||
free(args->filename);
|
||||
free(args->basename);
|
||||
free(args->basename_);
|
||||
free(args);
|
||||
|
||||
js_std_loop(ctx);
|
||||
|
@ -3315,7 +3315,7 @@ static JSValue js_worker_ctor(JSContext *ctx, JSValueConst new_target,
|
|||
goto oom_fail;
|
||||
bzero(args, sizeof(*args));
|
||||
args->filename = strdup(filename);
|
||||
args->basename = strdup(basename);
|
||||
args->basename_ = strdup(basename);
|
||||
|
||||
/* ports */
|
||||
args->recv_pipe = js_new_message_pipe();
|
||||
|
@ -3349,7 +3349,7 @@ static JSValue js_worker_ctor(JSContext *ctx, JSValueConst new_target,
|
|||
JS_FreeCString(ctx, filename);
|
||||
if (args) {
|
||||
free(args->filename);
|
||||
free(args->basename);
|
||||
free(args->basename_);
|
||||
js_free_message_pipe(args->recv_pipe);
|
||||
js_free_message_pipe(args->send_pipe);
|
||||
free(args);
|
||||
|
|
|
@ -960,7 +960,7 @@ int main(int argc, char *argv[]) {
|
|||
fin = fdopen(pipefds[0], "r");
|
||||
t = NewTrace();
|
||||
for (ev = 0, lineno = 1; !interrupted && (line = xgetline(fin)); ++lineno) {
|
||||
chomp(line);
|
||||
_chomp(line);
|
||||
Parse(t, line, lineno);
|
||||
free(line);
|
||||
for (; ev < t->events.n && !t->events.p[ev].is_interrupted; ++ev) {
|
||||
|
|
|
@ -152,7 +152,7 @@ int main(int argc, char *argv[]) {
|
|||
int y, x;
|
||||
ShowCrashReports();
|
||||
f = stdin;
|
||||
while ((s = chomp(xgetline(f)))) {
|
||||
while ((s = _chomp(xgetline(f)))) {
|
||||
n = strwidth(s, 0);
|
||||
xn = MAX(xn, n);
|
||||
T = xrealloc(T, ++yn * sizeof(*T));
|
||||
|
|
|
@ -113,6 +113,7 @@
|
|||
(let ((stab (copy-syntax-table)))
|
||||
(with-syntax-table stab
|
||||
(modify-syntax-entry ?+ " ")
|
||||
(modify-syntax-entry ?* " ")
|
||||
(let ((thing (thing-at-point 'symbol no-properties)))
|
||||
(when thing
|
||||
(intern thing))))))
|
||||
|
@ -146,6 +147,7 @@
|
|||
;; M-3 C-c C-c Compile w/ MODE=rel
|
||||
;; M-4 C-c C-c Compile w/ MODE=dbg
|
||||
;; M-5 C-c C-c Compile w/ MODE=""
|
||||
;; M-7 C-c C-c Compile w/ MODE=tinylinux
|
||||
;; M-8 C-c C-c Compile w/ llvm
|
||||
;; M-9 C-c C-c Compile w/ chibicc
|
||||
|
||||
|
@ -162,6 +164,7 @@
|
|||
((eq arg 3) "rel")
|
||||
((eq arg 4) "dbg")
|
||||
((eq arg 5) "")
|
||||
((eq arg 7) "tinylinux")
|
||||
((eq arg 8) "llvm")
|
||||
(default default)
|
||||
((cosmo-intest) "dbg")
|
||||
|
|
|
@ -38,7 +38,7 @@ int main(int argc, char *argv[]) {
|
|||
ShowCrashReports();
|
||||
f = fopen("/tmp/syms.txt", "r");
|
||||
memset(tabs, '\t', 64);
|
||||
while ((sym = chomp(xgetline(f)))) {
|
||||
while ((sym = _chomp(xgetline(f)))) {
|
||||
if (strlen(sym)) {
|
||||
printf("imp\t");
|
||||
|
||||
|
|
|
@ -120,7 +120,7 @@ int main(int argc, char *argv[]) {
|
|||
}
|
||||
} else {
|
||||
while ((getline(&line_, &linecap_, stdin)) != -1) {
|
||||
processarg(chomp(line_));
|
||||
processarg(_chomp(line_));
|
||||
}
|
||||
free_s(&line_);
|
||||
}
|
||||
|
|
|
@ -131,7 +131,7 @@ void processfile(void) {
|
|||
int col, s;
|
||||
size_t off, len;
|
||||
while ((getline(&line_, &linecap_, fi_)) != -1) {
|
||||
chomp(line_);
|
||||
_chomp(line_);
|
||||
len = strlen(line_);
|
||||
s = concat(&pool_, line_, len + 1);
|
||||
if (len < USHRT_MAX) {
|
||||
|
|
|
@ -148,7 +148,7 @@ void ProcessFile(void) {
|
|||
fg1 = -1u;
|
||||
glyph1 = -1u;
|
||||
while ((getline(&line_, &linecap_, in_)) != -1) {
|
||||
p = chomp(line_);
|
||||
p = _chomp(line_);
|
||||
sscanf(p, "%x, %u,%u,%u", &color, &bg, &fg, &glyph);
|
||||
if (color != color1) {
|
||||
if (color1 != -1u) {
|
||||
|
|
Loading…
Reference in a new issue