Fix basename() and dirname()

This commit is contained in:
Justine Tunney 2022-04-06 00:13:44 -07:00
parent 9b11206ae3
commit 04d39d47f1
41 changed files with 489 additions and 207 deletions

View file

@ -121,7 +121,7 @@ void SpellChecker(void) {
printf("word: "); printf("word: ");
fflush(stdout); fflush(stdout);
if (getline(&line, &linesize, stdin) > 0) { if (getline(&line, &linesize, stdin) > 0) {
query = strtolower(chomp(line)); query = strtolower(_chomp(line));
if (critbit0_contains(&words, query)) { if (critbit0_contains(&words, query)) {
printf("ok\r\n"); printf("ok\r\n");
} else { } else {
@ -147,7 +147,7 @@ void SpellChecker(void) {
void LoadWords(void) { void LoadWords(void) {
CHECK_NOTNULL((f = fopen("/zip/usr/share/dict/words", "r"))); CHECK_NOTNULL((f = fopen("/zip/usr/share/dict/words", "r")));
while (getline(&line, &linesize, f) > 0) { while (getline(&line, &linesize, f) > 0) {
critbit0_insert(&words, strtolower(chomp(line))); critbit0_insert(&words, strtolower(_chomp(line)));
} }
CHECK_NE(-1, fclose(f)); CHECK_NE(-1, fclose(f));
} }

View file

@ -1673,7 +1673,7 @@ char* GetLine(void) {
static char* line; static char* line;
static size_t linesize; static size_t linesize;
if (getline(&line, &linesize, stdin) > 0) { if (getline(&line, &linesize, stdin) > 0) {
return chomp(line); return _chomp(line);
} else { } else {
return NULL; return NULL;
} }

View file

@ -17,15 +17,23 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/nt/enum/filetype.h"
#include "libc/nt/files.h" #include "libc/nt/files.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
textwindows int64_t sys_lseek_nt(int fd, int64_t offset, int whence) { textwindows int64_t sys_lseek_nt(int fd, int64_t offset, int whence) {
int64_t res; int64_t res;
if (!__isfdkind(fd, kFdFile)) return ebadf(); if (__isfdkind(fd, kFdFile)) {
if (SetFilePointerEx(g_fds.p[fd].handle, offset, &res, whence)) { if (GetFileType(g_fds.p[fd].handle) != kNtFileTypePipe) {
return res; if (SetFilePointerEx(g_fds.p[fd].handle, offset, &res, whence)) {
return res;
} else {
return __winerr();
}
} else {
return espipe();
}
} else { } else {
return __winerr(); return ebadf();
} }
} }

View file

@ -53,8 +53,8 @@
static textwindows int64_t sys_open_nt_impl(int dirfd, const char *path, static textwindows int64_t sys_open_nt_impl(int dirfd, const char *path,
uint32_t flags, int32_t mode) { uint32_t flags, int32_t mode) {
uint32_t br;
int64_t handle; int64_t handle;
uint32_t br, err;
char16_t path16[PATH_MAX]; char16_t path16[PATH_MAX];
uint32_t perm, share, disp, attr; uint32_t perm, share, disp, attr;
if (__mkntpathat(dirfd, path, flags, path16) == -1) return -1; 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 { } else {
attr = kNtFileAttributeNormal; attr = kNtFileAttributeNormal;
if (flags & _O_DIRECTORY) attr |= kNtFileFlagBackupSemantics; 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; flags |= kNtFileFlagOverlapped;
if (~flags & _O_INDEXED) attr |= kNtFileAttributeNotContentIndexed; 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_DIRECT) attr |= kNtFileFlagNoBuffering;
if (flags & _O_NDELAY) attr |= kNtFileFlagWriteThrough; if (flags & _O_NDELAY) attr |= kNtFileFlagWriteThrough;
if ((handle = CreateFile(path16, perm, share, &kNtIsInheritable, disp, attr, return CreateFile(path16, perm, share, &kNtIsInheritable, disp, attr, 0);
0)) != -1) {
} else if (GetLastError() == kNtErrorFileExists &&
((flags & _O_CREAT) &&
(flags & _O_TRUNC))) { /* TODO(jart): What was this? */
handle = eisdir();
}
return handle;
} }
static textwindows ssize_t sys_open_nt_console(int dirfd, static textwindows ssize_t sys_open_nt_console(int dirfd,

View file

@ -21,13 +21,13 @@
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/fmt/conv.h" #include "libc/fmt/conv.h"
#include "libc/fmt/isslash.internal.h"
#include "libc/fmt/itoa.h" #include "libc/fmt/itoa.h"
#include "libc/nt/createfile.h" #include "libc/nt/createfile.h"
#include "libc/nt/enum/accessmask.h" #include "libc/nt/enum/accessmask.h"
#include "libc/nt/enum/creationdisposition.h" #include "libc/nt/enum/creationdisposition.h"
#include "libc/nt/enum/fileflagandattributes.h" #include "libc/nt/enum/fileflagandattributes.h"
#include "libc/nt/enum/filesharemode.h" #include "libc/nt/enum/filesharemode.h"
#include "libc/str/path.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/sysv/consts/at.h" #include "libc/sysv/consts/at.h"
#include "libc/sysv/consts/o.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"; if (!name) name = "openanon";
for (i = 0; p < pe; ++i) { for (i = 0; p < pe; ++i) {
if (!(c = name[i])) break; if (!(c = name[i])) break;
if (isslash(c)) c = '_'; if (_isdirsep(c)) c = '_';
*p++ = c; *p++ = c;
} }
*p++ = '.'; *p++ = '.';

View file

@ -29,6 +29,7 @@
#include "libc/mem/alloca.h" #include "libc/mem/alloca.h"
#include "libc/nt/runtime.h" #include "libc/nt/runtime.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/str/path.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/str/tpenc.h" #include "libc/str/tpenc.h"
#include "libc/str/utf16.h" #include "libc/str/utf16.h"

View file

@ -17,19 +17,42 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/fmt/conv.h" #include "libc/fmt/conv.h"
#include "libc/fmt/isslash.internal.h" #include "libc/str/path.h"
#include "libc/str/str.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 * Both / and \ are are considered valid component separators on all
* platforms. Trailing slashes are ignored. We don't grant special * platforms. Trailing slashes are ignored. We don't grant special
* consideration to things like foo/., c:/, \\?\Volume, etc. * consideration to things like foo/., c:/, \\?\Volume, etc.
* *
* @param path is NUL-terminated UTF-8 path * @param path is UTF-8 and may be mutated, but not expanded in length
* @return pointer inside path or path itself * @return pointer to path, or inside path, or to a special r/o string
* @see dirname()
* @see SUSv2
*/ */
textstartup char *basename(const char *path) { char *basename(char *path) {
return basename_n(path, strlen(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 ".";
}
} }

View file

@ -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;
}

View file

@ -42,13 +42,13 @@ size_t wcsxfrm(wchar_t *, const wchar_t *, size_t);
cosmopolitan § conversion » time cosmopolitan § conversion » time
*/ */
int64_t DosDateTimeToUnix(unsigned, unsigned) dontthrow; int64_t DosDateTimeToUnix(unsigned, unsigned) libcesque nosideeffect;
struct timeval WindowsTimeToTimeVal(int64_t) dontthrow; struct timeval WindowsTimeToTimeVal(int64_t) libcesque nosideeffect;
struct timespec WindowsTimeToTimeSpec(int64_t) dontthrow; struct timespec WindowsTimeToTimeSpec(int64_t) libcesque nosideeffect;
int64_t TimeSpecToWindowsTime(struct timespec) dontthrow; int64_t TimeSpecToWindowsTime(struct timespec) libcesque nosideeffect;
int64_t TimeValToWindowsTime(struct timeval) dontthrow; int64_t TimeValToWindowsTime(struct timeval) libcesque nosideeffect;
struct timeval WindowsDurationToTimeVal(int64_t) dontthrow; struct timeval WindowsDurationToTimeVal(int64_t) libcesque nosideeffect;
struct timespec WindowsDurationToTimeSpec(int64_t) dontthrow; struct timespec WindowsDurationToTimeSpec(int64_t) libcesque nosideeffect;
static inline struct NtFileTime MakeFileTime(int64_t x) { static inline struct NtFileTime MakeFileTime(int64_t x) {
return (struct NtFileTime){(uint32_t)x, (uint32_t)(x >> 32)}; 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 *dirname(char *);
char *basename(const char *) nosideeffect; char *basename(char *);
char *basename_n(const char *, size_t) nosideeffect;
bool isabspath(const char *) paramsnonnull() nosideeffect;
char *stripext(char *); char *stripext(char *);
char *stripexts(char *); char *stripexts(char *);

View file

@ -17,34 +17,42 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/fmt/conv.h" #include "libc/fmt/conv.h"
#include "libc/str/path.h"
#include "libc/str/str.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 * path dirname() basename()
* this returns empty string. *
* . . .
* .. . ..
* / / /
* 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) { char *dirname(char *path) {
size_t i, n; size_t i;
if (!(n = strlen(s))) return s; if (path && *path) {
while (n && ISDELIM(s[n - 1])) --n; i = strlen(path) - 1;
if (n) { for (; _isdirsep(path[i]); i--) {
while (n && !ISSLASH(s[n - 1])) --n; if (!i) return "/";
if (n) {
while (n && ISDELIM(s[n - 1])) --n;
if (!n) ++n;
} else {
s[n++] = '.';
} }
for (; !_isdirsep(path[i]); i--) {
if (!i) return ".";
}
for (; _isdirsep(path[i]); i--) {
if (!i) return "/";
}
path[i + 1] = 0;
return path;
} else { } else {
++n; return ".";
} }
s[n] = '\0';
return s;
} }

View file

@ -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_ */

View file

@ -36,6 +36,7 @@ kDos2Errno:
.e kNtErrorBadNetName,ENOENT .e kNtErrorBadNetName,ENOENT
.e kNtErrorBadNetResp,ENETDOWN .e kNtErrorBadNetResp,ENETDOWN
.e kNtErrorBadPathname,ENOENT .e kNtErrorBadPathname,ENOENT
.e kNtErrorFileExists,EEXIST
.e kNtErrorCannotMake,EACCES .e kNtErrorCannotMake,EACCES
.e kNtErrorCommitmentLimit,ENOMEM .e kNtErrorCommitmentLimit,ENOMEM
.e kNtErrorConnectionAborted,ECONNABORTED .e kNtErrorConnectionAborted,ECONNABORTED

View file

@ -19,6 +19,7 @@
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/mem/mem.h" #include "libc/mem/mem.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/str/path.h"
/** /**
* Returns current working directory. * Returns current working directory.

View file

@ -25,7 +25,7 @@
* *
* This function is similar to getline() except it'll truncate lines * This function is similar to getline() except it'll truncate lines
* exceeding size. The line ending marker is included and may be removed * exceeding size. The line ending marker is included and may be removed
* using chomp(). * using _chomp().
*/ */
char *fgets(char *s, int size, FILE *f) { char *fgets(char *s, int size, FILE *f) {
int c; int c;

View file

@ -36,7 +36,7 @@
* @return number of bytes read >0, including delim, excluding NUL, * @return number of bytes read >0, including delim, excluding NUL,
* or -1 w/ errno on EOF or error; see ferror() and feof() * or -1 w/ errno on EOF or error; see ferror() and feof()
* @note this function can't punt EINTR to caller * @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) { ssize_t getdelim(char **s, size_t *n, int delim, FILE *f) {
char *p; char *p;

View file

@ -23,7 +23,7 @@
* *
* This function delegates to getdelim(), which provides further * This function delegates to getdelim(), which provides further
* documentation. Concerning lines, please note the \n or \r\n are * 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 * @param line is the caller's buffer (in/out) which is extended
* automatically. *line may be NULL but only if *n is 0; * automatically. *line may be NULL but only if *n is 0;

View file

@ -24,7 +24,7 @@
* @param line is NULL-propagating * @param line is NULL-propagating
* @see getline * @see getline
*/ */
char *chomp(char *line) { char *_chomp(char *line) {
size_t i; size_t i;
if (line) { if (line) {
for (i = strlen(line); i--;) { for (i = strlen(line); i--;) {

View file

@ -24,7 +24,16 @@
* @param line is NULL-propagating * @param line is NULL-propagating
* @see getline * @see getline
*/ */
char16_t *chomp16(char16_t *line) { char16_t *_chomp16(char16_t *line) {
if (line) line[strcspn16(line, u"\r\n")] = '\0'; size_t i;
if (line) {
for (i = strlen16(line); i--;) {
if (line[i] == '\r' || line[i] == '\n') {
line[i] = '\0';
} else {
break;
}
}
}
return line; return line;
} }

154
libc/str/classifypath.c Normal file
View 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;
}
}

View file

@ -43,8 +43,8 @@ static textwindows bool shouldquotedos(const char16_t c) {
* Escapes command so DOS can run it. * Escapes command so DOS can run it.
* @see Iain Patterson's NSSM for original code in public domain * @see Iain Patterson's NSSM for original code in public domain
*/ */
textwindows bool escapedos(char16_t *buffer, unsigned buflen, textwindows bool _escapedos(char16_t *buffer, unsigned buflen,
const char16_t *unquoted, unsigned len) { const char16_t *unquoted, unsigned len) {
unsigned i, j, n; unsigned i, j, n;
if (len > buflen - 1) return false; if (len > buflen - 1) return false;
bool escape = false; bool escape = false;

View file

@ -1,7 +1,7 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ /*-*- 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 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 Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the 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 TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/dce.h" #include "libc/str/path.h"
#include "libc/str/str.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 * - `/home/jart/foo.txt` is absolute
* - `C:/Users/jart/foo.txt` is absolute on NT * - `C:/Users/jart/foo.txt` is absolute on Windows
* - `C:\Users\jart\foo.txt` is absolute on NT * - `C:\Users\jart\foo.txt` is absolute on Windows
* - `\??\C:\Users\jart\foo.txt` is absolute on NT * - `\??\C:\Users\jart\foo.txt` is absolute on Windows
* - `\\.\C:\Users\jart\foo.txt` is absolute on NT * - `\\.\C:\Users\jart\foo.txt` is absolute on Windows
* - `/Users/jart/foo.txt` we consider it absolute enough on NT * - `/Users/jart/foo.txt` is effectively absolute on Windows
* - `\Users\jart\foo.txt` we consider it absolute enough on NT * - `\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) { bool _isabspath(const char *path) {
if (*p == '/') { return _classifypath(path) & _PATH_ABS;
return true;
}
if (IsWindows() &&
(*p == '/' || *p == '\\' || (isalpha(p[0]) && p[1] == ':'))) {
return true;
}
return false;
} }

View file

@ -1,7 +1,7 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ /*-*- 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 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 Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the 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 TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/fmt/conv.h" #include "libc/dce.h"
#include "libc/fmt/isslash.internal.h" #include "libc/str/str.h"
/** /**
* Returns true if pathname could be absolute on any known platform. * Returns true if character is directory separator slash.
*
* 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.
*/ */
bool isabspath(const char *path) { bool _isdirsep(int c) {
if (isslash(*path)) return true; return c == '/' || c == '\\';
for (; *path; ++path) {
if (isslash(*path)) return false;
if (*path == ':') {
++path;
if (isslash(*path)) return true;
}
}
return false;
} }

20
libc/str/path.h Normal file
View 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_ */

View file

@ -196,17 +196,16 @@ char *strerror(int) returnsnonnull dontthrow nocallback;
long a64l(const char *); long a64l(const char *);
char *l64a(long); char *l64a(long);
char *strntolower(char *, size_t); char *strntolower(char *, size_t) libcesque;
char *strtolower(char *) paramsnonnull(); char *strtolower(char *) libcesque paramsnonnull();
char *strntoupper(char *, size_t); char *strntoupper(char *, size_t) libcesque;
char *strtoupper(char *) paramsnonnull(); char *strtoupper(char *) libcesque paramsnonnull();
char *chomp(char *); char *_chomp(char *) libcesque;
char16_t *chomp16(char16_t *); char16_t *_chomp16(char16_t *) libcesque;
wchar_t *wchomp(wchar_t *); wchar_t *_wchomp(wchar_t *) libcesque;
bool _istext(const void *, size_t); bool _istext(const void *, size_t) libcesque;
bool _isutf8(const void *, size_t); bool _isutf8(const void *, size_t) libcesque;
bool _isabspath(const char *) strlenesque; bool _escapedos(char16_t *, unsigned, const char16_t *, unsigned) libcesque;
bool escapedos(char16_t *, unsigned, const char16_t *, unsigned);
/*───────────────────────────────────────────────────────────────────────────│─╗ /*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § strings » multibyte cosmopolitan § strings » multibyte

View file

@ -24,7 +24,16 @@
* @param line is NULL-propagating * @param line is NULL-propagating
* @see getline * @see getline
*/ */
wchar_t *wchomp(wchar_t *line) { wchar_t *_wchomp(wchar_t *line) {
if (line) line[wcscspn(line, L"\r\n")] = '\0'; size_t i;
if (line) {
for (i = wcslen(line); i--;) {
if (line[i] == '\r' || line[i] == '\n') {
line[i] = '\0';
} else {
break;
}
}
}
return line; return line;
} }

View file

@ -17,11 +17,12 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/fmt/conv.h" #include "libc/fmt/conv.h"
#include "libc/runtime/gc.internal.h"
#include "libc/x/x.h" #include "libc/x/x.h"
/** /**
* Returns directory portion of path. * Returns directory portion of path.
*/ */
char *xdirname(const char *path) { char *xdirname(const char *path) {
return dirname(xstrdup(path)); return xstrdup(dirname(gc(xstrdup(path))));
} }

View file

@ -23,10 +23,10 @@
/** /**
* Reads line from stream. * 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() * or NULL on ferror() or feof()
* @see getdelim() for a more difficult api * @see getdelim() for a more difficult api
* @see chomp() * @see _chomp()
*/ */
char *xgetline(FILE *f) { char *xgetline(FILE *f) {
char *p; char *p;

View file

@ -17,6 +17,7 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/bits/safemacros.internal.h" #include "libc/bits/safemacros.internal.h"
#include "libc/str/path.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/x/x.h" #include "libc/x/x.h"

View file

@ -25,7 +25,7 @@ void LogCertificate(const char *msg, mbedtls_x509_crt *cert) {
if (LOGGABLE(kLogDebug)) { if (LOGGABLE(kLogDebug)) {
if ((s = malloc((n = 15000)))) { if ((s = malloc((n = 15000)))) {
if (mbedtls_x509_crt_info(s, n, " ", cert) > 0) { 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); free(s);
} }

View file

@ -54,9 +54,9 @@ TEST(mkdir, testPathIsDirectory_EEXIST) {
EXPECT_EQ(EEXIST, errno); EXPECT_EQ(EEXIST, errno);
} }
TEST(makedirs, testEmptyString_ENOENT) { TEST(makedirs, testEmptyString_EEXIST) {
EXPECT_EQ(-1, makedirs("", 0755)); EXPECT_EQ(-1, makedirs("", 0755));
EXPECT_EQ(ENOENT, errno); EXPECT_EQ(EEXIST, errno);
} }
TEST(mkdirat, testRelativePath_opensRelativeToDirFd) { TEST(mkdirat, testRelativePath_opensRelativeToDirFd) {

View file

@ -21,25 +21,33 @@
#include "libc/mem/mem.h" #include "libc/mem/mem.h"
#include "libc/testlib/testlib.h" #include "libc/testlib/testlib.h"
TEST(basename, test) { #define BASENAME(x) basename(gc(strdup(x)))
EXPECT_STREQ("", basename(""));
EXPECT_STREQ("/", basename("/")); TEST(basename, testRegularExamples) {
EXPECT_STREQ("hello", basename("hello")); EXPECT_STREQ("lib", BASENAME("/usr/lib"));
EXPECT_STREQ("there", basename("hello/there")); EXPECT_STREQ("lib", BASENAME("usr/lib"));
EXPECT_STREQ("yo", basename("hello/there/yo")); 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) { 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) { TEST(basename, testOnlySlashes_oneSlashOnlyVasily) {
EXPECT_STREQ("/", basename("///")); EXPECT_STREQ("/", BASENAME("///"));
} }
TEST(basename, testWindows_isGrantedRespect) { TEST(basename, testWindows_isGrantedRespect) {
EXPECT_STREQ("there", basename("hello\\there")); EXPECT_STREQ("there", BASENAME("hello\\there"));
EXPECT_STREQ("yo", basename("hello\\there\\yo")); EXPECT_STREQ("yo", BASENAME("hello\\there\\yo"));
} }

View file

@ -26,12 +26,11 @@
TEST(dirname, test) { TEST(dirname, test) {
EXPECT_STREQ("/usr/lib", dirname(gc(strdup("/usr/lib/foo.bar")))); 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("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("usr"))));
EXPECT_STREQ("/", dirname(gc(strdup("/")))); 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(".."))));
EXPECT_STREQ("", dirname(gc(strdup("")))); EXPECT_STREQ(".", dirname(gc(strdup(""))));
} }

View 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:/"));
}

View file

@ -3063,7 +3063,7 @@ typedef struct {
typedef struct { typedef struct {
char *filename; /* module filename */ char *filename; /* module filename */
char *basename; /* module base name */ char *basename_; /* module base name */
JSWorkerMessagePipe *recv_pipe, *send_pipe; JSWorkerMessagePipe *recv_pipe, *send_pipe;
} WorkerFuncArgs; } WorkerFuncArgs;
@ -3231,10 +3231,10 @@ static void *worker_func(void *opaque)
js_std_add_helpers(ctx, -1, NULL); 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); js_std_dump_error(ctx);
free(args->filename); free(args->filename);
free(args->basename); free(args->basename_);
free(args); free(args);
js_std_loop(ctx); js_std_loop(ctx);
@ -3315,7 +3315,7 @@ static JSValue js_worker_ctor(JSContext *ctx, JSValueConst new_target,
goto oom_fail; goto oom_fail;
bzero(args, sizeof(*args)); bzero(args, sizeof(*args));
args->filename = strdup(filename); args->filename = strdup(filename);
args->basename = strdup(basename); args->basename_ = strdup(basename);
/* ports */ /* ports */
args->recv_pipe = js_new_message_pipe(); 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); JS_FreeCString(ctx, filename);
if (args) { if (args) {
free(args->filename); free(args->filename);
free(args->basename); free(args->basename_);
js_free_message_pipe(args->recv_pipe); js_free_message_pipe(args->recv_pipe);
js_free_message_pipe(args->send_pipe); js_free_message_pipe(args->send_pipe);
free(args); free(args);

View file

@ -960,7 +960,7 @@ int main(int argc, char *argv[]) {
fin = fdopen(pipefds[0], "r"); fin = fdopen(pipefds[0], "r");
t = NewTrace(); t = NewTrace();
for (ev = 0, lineno = 1; !interrupted && (line = xgetline(fin)); ++lineno) { for (ev = 0, lineno = 1; !interrupted && (line = xgetline(fin)); ++lineno) {
chomp(line); _chomp(line);
Parse(t, line, lineno); Parse(t, line, lineno);
free(line); free(line);
for (; ev < t->events.n && !t->events.p[ev].is_interrupted; ++ev) { for (; ev < t->events.n && !t->events.p[ev].is_interrupted; ++ev) {

View file

@ -152,7 +152,7 @@ int main(int argc, char *argv[]) {
int y, x; int y, x;
ShowCrashReports(); ShowCrashReports();
f = stdin; f = stdin;
while ((s = chomp(xgetline(f)))) { while ((s = _chomp(xgetline(f)))) {
n = strwidth(s, 0); n = strwidth(s, 0);
xn = MAX(xn, n); xn = MAX(xn, n);
T = xrealloc(T, ++yn * sizeof(*T)); T = xrealloc(T, ++yn * sizeof(*T));

View file

@ -113,6 +113,7 @@
(let ((stab (copy-syntax-table))) (let ((stab (copy-syntax-table)))
(with-syntax-table stab (with-syntax-table stab
(modify-syntax-entry ?+ " ") (modify-syntax-entry ?+ " ")
(modify-syntax-entry ?* " ")
(let ((thing (thing-at-point 'symbol no-properties))) (let ((thing (thing-at-point 'symbol no-properties)))
(when thing (when thing
(intern thing)))))) (intern thing))))))
@ -146,6 +147,7 @@
;; M-3 C-c C-c Compile w/ MODE=rel ;; M-3 C-c C-c Compile w/ MODE=rel
;; M-4 C-c C-c Compile w/ MODE=dbg ;; M-4 C-c C-c Compile w/ MODE=dbg
;; M-5 C-c C-c Compile w/ MODE="" ;; 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-8 C-c C-c Compile w/ llvm
;; M-9 C-c C-c Compile w/ chibicc ;; M-9 C-c C-c Compile w/ chibicc
@ -162,6 +164,7 @@
((eq arg 3) "rel") ((eq arg 3) "rel")
((eq arg 4) "dbg") ((eq arg 4) "dbg")
((eq arg 5) "") ((eq arg 5) "")
((eq arg 7) "tinylinux")
((eq arg 8) "llvm") ((eq arg 8) "llvm")
(default default) (default default)
((cosmo-intest) "dbg") ((cosmo-intest) "dbg")

View file

@ -38,7 +38,7 @@ int main(int argc, char *argv[]) {
ShowCrashReports(); ShowCrashReports();
f = fopen("/tmp/syms.txt", "r"); f = fopen("/tmp/syms.txt", "r");
memset(tabs, '\t', 64); memset(tabs, '\t', 64);
while ((sym = chomp(xgetline(f)))) { while ((sym = _chomp(xgetline(f)))) {
if (strlen(sym)) { if (strlen(sym)) {
printf("imp\t"); printf("imp\t");

View file

@ -120,7 +120,7 @@ int main(int argc, char *argv[]) {
} }
} else { } else {
while ((getline(&line_, &linecap_, stdin)) != -1) { while ((getline(&line_, &linecap_, stdin)) != -1) {
processarg(chomp(line_)); processarg(_chomp(line_));
} }
free_s(&line_); free_s(&line_);
} }

View file

@ -131,7 +131,7 @@ void processfile(void) {
int col, s; int col, s;
size_t off, len; size_t off, len;
while ((getline(&line_, &linecap_, fi_)) != -1) { while ((getline(&line_, &linecap_, fi_)) != -1) {
chomp(line_); _chomp(line_);
len = strlen(line_); len = strlen(line_);
s = concat(&pool_, line_, len + 1); s = concat(&pool_, line_, len + 1);
if (len < USHRT_MAX) { if (len < USHRT_MAX) {

View file

@ -148,7 +148,7 @@ void ProcessFile(void) {
fg1 = -1u; fg1 = -1u;
glyph1 = -1u; glyph1 = -1u;
while ((getline(&line_, &linecap_, in_)) != -1) { while ((getline(&line_, &linecap_, in_)) != -1) {
p = chomp(line_); p = _chomp(line_);
sscanf(p, "%x, %u,%u,%u", &color, &bg, &fg, &glyph); sscanf(p, "%x, %u,%u,%u", &color, &bg, &fg, &glyph);
if (color != color1) { if (color != color1) {
if (color1 != -1u) { if (color1 != -1u) {