mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-01-31 03:27:39 +00:00
Implement getcwd() for XNU
This commit is contained in:
parent
417797d218
commit
95173645a1
17 changed files with 239 additions and 77 deletions
|
@ -11,12 +11,31 @@
|
|||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "third_party/xed/x86.h"
|
||||
|
||||
/**
|
||||
* @fileoverview x86 instruction length decoder by way of hex pipe.
|
||||
*/
|
||||
|
||||
int fgethex(FILE *f) {
|
||||
int o, t = -1;
|
||||
while (!((o = fgetc(f)) & ~0xFF)) {
|
||||
switch (t) {
|
||||
case -1:
|
||||
t = isxdigit(o) ? hextoint(o) : -1;
|
||||
break;
|
||||
default:
|
||||
if (isxdigit(o)) {
|
||||
return t * 16 + hextoint(o);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (t >= 0) return einval();
|
||||
return -1;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[argc]) {
|
||||
unsigned c, i, j, l;
|
||||
enum XedError err;
|
||||
|
@ -42,9 +61,8 @@ int main(int argc, char *argv[argc]) {
|
|||
l = xedd.length;
|
||||
if (l <= 0 || l > i) abort();
|
||||
for (j = 0; j < l; ++j) {
|
||||
if (fputhex(buf[j], stdout) == -1) {
|
||||
return errno;
|
||||
}
|
||||
fputc("0123456789ABCDEF"[(buf[j] & 0xf0) >> 4], stdout);
|
||||
fputc("0123456789ABCDEF"[(buf[j] & 0x0f) >> 0], stdout);
|
||||
}
|
||||
putchar('\n');
|
||||
memcpy(&buf[0], &buf[l], i -= l);
|
||||
|
|
|
@ -232,10 +232,6 @@ int prctl();
|
|||
int sysctl(const int *, unsigned, void *, size_t *, void *, size_t);
|
||||
int fchdir(int);
|
||||
|
||||
#define getcwd(BUF, SIZE) \
|
||||
(__builtin_constant_p(BUF) && (&(BUF)[0] == NULL) ? get_current_dir_name() \
|
||||
: getcwd(BUF, SIZE))
|
||||
|
||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||
│ cosmopolitan § system calls » formatting ─╬─│┼
|
||||
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||
|
@ -248,6 +244,10 @@ int vdprintf(int, const char *, va_list) paramsnonnull();
|
|||
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||
#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
|
||||
|
||||
#define getcwd(BUF, SIZE) \
|
||||
(__builtin_constant_p(BUF) && !(BUF) ? get_current_dir_name() \
|
||||
: getcwd(BUF, SIZE))
|
||||
|
||||
void _init_onntconsoleevent(void);
|
||||
void _init_wincrash(void);
|
||||
|
||||
|
|
|
@ -23,12 +23,12 @@
|
|||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
textwindows char *getcwd$nt(char *buf, size_t size) {
|
||||
uint16_t name16[PATH_MAX + 1];
|
||||
uint16_t name16[PATH_MAX];
|
||||
if (GetCurrentDirectory(ARRAYLEN(name16), name16)) {
|
||||
tprecode16to8(buf, size, name16);
|
||||
return buf;
|
||||
} else {
|
||||
__winerr();
|
||||
return NULL;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
|
57
libc/calls/getcwd-xnu.c
Normal file
57
libc/calls/getcwd-xnu.c
Normal file
|
@ -0,0 +1,57 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ 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/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
#define XNU_F_GETPATH 50
|
||||
#define XNU_MAXPATHLEN 1024
|
||||
|
||||
char *getcwd$xnu(char *res, size_t size) {
|
||||
int fd;
|
||||
struct stat st[2];
|
||||
char buf[XNU_MAXPATHLEN], *ret = NULL;
|
||||
if ((fd = openat$sysv(AT_FDCWD, ".", O_RDONLY | O_DIRECTORY)) != -1) {
|
||||
if (fstat$sysv(fd, &st[0]) != -1) {
|
||||
if (st[0].st_dev && st[0].st_ino) {
|
||||
if (fcntl$sysv(fd, XNU_F_GETPATH, buf) != -1) {
|
||||
if (fstatat$sysv(AT_FDCWD, buf, &st[1], 0) != -1) {
|
||||
if (st[0].st_dev == st[1].st_dev && st[0].st_ino == st[1].st_ino) {
|
||||
if (memccpy(res, buf, '\0', size)) {
|
||||
ret = res;
|
||||
} else {
|
||||
erange();
|
||||
}
|
||||
} else {
|
||||
einval();
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
einval();
|
||||
}
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
return ret;
|
||||
}
|
|
@ -19,8 +19,6 @@
|
|||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Returns current working directory.
|
||||
|
@ -34,28 +32,16 @@
|
|||
* @error ERANGE, EINVAL
|
||||
*/
|
||||
char *(getcwd)(char *buf, size_t size) {
|
||||
if (buf) {
|
||||
buf[0] = '\0';
|
||||
if (!IsWindows()) {
|
||||
int olderr = errno;
|
||||
if (getcwd$sysv(buf, size) != NULL) {
|
||||
return buf;
|
||||
} else if (IsXnu() && errno == ENOSYS) {
|
||||
if (size >= 2) {
|
||||
buf[0] = '.'; /* XXX: could put forth more effort */
|
||||
buf[1] = '\0';
|
||||
errno = olderr;
|
||||
return buf;
|
||||
} else {
|
||||
erange();
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
if (buf && size) buf[0] = '\0';
|
||||
if (!IsWindows()) {
|
||||
if (IsXnu()) {
|
||||
return getcwd$xnu(buf, size);
|
||||
} else if (getcwd$sysv(buf, size) != (void *)-1) {
|
||||
return buf;
|
||||
} else {
|
||||
return getcwd$nt(buf, size);
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
efault();
|
||||
return NULL;
|
||||
return getcwd$nt(buf, size);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,7 +32,6 @@
|
|||
*/
|
||||
nodiscard char *get_current_dir_name(void) {
|
||||
char *buf, *res;
|
||||
if ((res = getenv("PWD"))) return strdup(res);
|
||||
if (!(buf = malloc(PATH_MAX))) return NULL;
|
||||
if (!(res = (getcwd)(buf, PATH_MAX))) free(buf);
|
||||
return res;
|
||||
|
|
|
@ -99,6 +99,7 @@ forceinline size_t clampio(size_t size) {
|
|||
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||
|
||||
char *getcwd$sysv(char *, u64) hidden;
|
||||
char *getcwd$xnu(char *, u64) hidden;
|
||||
i32 __dup3$sysv(i32, i32, i32) hidden;
|
||||
i32 __execve$sysv(const char *, char *const[], char *const[]) hidden;
|
||||
i32 __fstat$sysv(i32, struct stat *) hidden;
|
||||
|
@ -120,7 +121,7 @@ i32 fchmod$sysv(i32, u32) hidden;
|
|||
i32 fchmodat$sysv(i32, const char *, u32, u32) hidden;
|
||||
i32 fchown$sysv(i64, u32, u32) hidden;
|
||||
i32 fchownat$sysv(i32, const char *, u32, u32, u32) hidden;
|
||||
i32 fcntl$sysv(i32, i32, i32) hidden;
|
||||
i32 fcntl$sysv(i32, i32, ...) hidden;
|
||||
i32 fdatasync$sysv(i32) hidden;
|
||||
i32 flock$sysv(i32, i32) hidden;
|
||||
i32 fork$sysv(void) hidden;
|
||||
|
@ -151,7 +152,7 @@ i32 mprotect$sysv(void *, u64, i32) hidden;
|
|||
i32 msync$sysv(void *, u64, i32) hidden;
|
||||
i32 munmap$sysv(void *, u64) hidden;
|
||||
i32 nanosleep$sysv(const struct timespec *, struct timespec *) hidden;
|
||||
i32 openat$sysv(i32, const char *, i32, i32) hidden;
|
||||
i32 openat$sysv(i32, const char *, i32, ...) hidden;
|
||||
i32 pause$sysv(void) hidden;
|
||||
i32 pipe$sysv(i32[hasatleast 2]) hidden;
|
||||
i32 pipe2$sysv(i32[hasatleast 2], u32) hidden;
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/safemacros.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/macros.h"
|
||||
|
@ -31,19 +32,31 @@
|
|||
* @return path to debug binary, or -1 w/ errno
|
||||
*/
|
||||
const char *FindDebugBinary(void) {
|
||||
static char buf[PATH_MAX];
|
||||
if (buf[0]) return &buf[0];
|
||||
const char *const trybins[] = {program_invocation_name,
|
||||
(const char *)getauxval(AT_EXECFN)};
|
||||
for (unsigned i = 0; i < ARRAYLEN(trybins); ++i) {
|
||||
const char *res = trybins[i];
|
||||
unsigned len = strlen(res);
|
||||
if (4 < len && len < sizeof(buf) - 5) {
|
||||
if (strcmp(res + len - 4, ".dbg") == 0) return res;
|
||||
/* try suffixing extension, e.g. .com → .com.dbg */
|
||||
memcpy(mempcpy(buf, res, len), ".dbg", 5);
|
||||
if (fileexists(buf)) return &buf[0];
|
||||
buf[0] = '\0';
|
||||
unsigned i, len;
|
||||
char buf[2][PATH_MAX];
|
||||
static char res[PATH_MAX];
|
||||
const char *bins[4], *pwd;
|
||||
bins[0] = program_invocation_name;
|
||||
bins[1] = (const char *)getauxval(AT_EXECFN);
|
||||
pwd = emptytonull(getenv("PWD"));
|
||||
for (i = 0; i < 2; ++i) {
|
||||
if (pwd && bins[i] && bins[i][0] != '/' && bins[i][0] != '\\' &&
|
||||
strlen(pwd) + 1 + strlen(bins[i]) + 1 <= ARRAYLEN(buf[0])) {
|
||||
strcpy(buf[i], pwd);
|
||||
strcat(buf[i], "/");
|
||||
strcat(buf[i], bins[i]);
|
||||
bins[i + 2] = buf[i];
|
||||
}
|
||||
}
|
||||
for (i = 0; i < 4; ++i) {
|
||||
if (!bins[i]) continue;
|
||||
len = strlen(bins[i]);
|
||||
memcpy(res, bins[i], len + 1);
|
||||
if (!endswith(res, ".dbg") && len + 3 + 1 <= ARRAYLEN(res)) {
|
||||
strcat(res, ".dbg");
|
||||
}
|
||||
if (fileexists(res)) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
errno = ENOENT;
|
||||
|
|
|
@ -52,8 +52,6 @@ int putchar(int);
|
|||
int puts(const char *) paramsnonnull();
|
||||
ssize_t getline(char **, size_t *, FILE *) paramsnonnull();
|
||||
ssize_t getdelim(char **, size_t *, int, FILE *) paramsnonnull();
|
||||
int fputhex(int, FILE *) paramsnonnull();
|
||||
int fgethex(FILE *) paramsnonnull();
|
||||
FILE *fopen(const char *, const char *) paramsnonnull() nodiscard;
|
||||
FILE *fdopen(int, const char *) paramsnonnull() nodiscard;
|
||||
FILE *fmemopen(void *, size_t, const char *) paramsnonnull((3)) nodiscard;
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
* This API was thought to be nearly extinct until recent versions
|
||||
* of Clang (c. 2019) started generating synthetic calls to it.
|
||||
*
|
||||
* @return unsigned char subtraction at stop index
|
||||
* @return 0 if a and b have equal contents, otherwise non-zero
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int bcmp(const void *a, const void *b, size_t n) {
|
||||
|
|
|
@ -151,11 +151,13 @@ int strcasecmpzbw(const uint16_t *, const char *) strlenesque;
|
|||
char *stpcpy(char *, const char *) memcpyesque;
|
||||
char *stpncpy(char *, const char *, size_t) memcpyesque;
|
||||
char *strcat(char *, const char *) memcpyesque;
|
||||
char16_t *strcat16(char16_t *, const char16_t *);
|
||||
char16_t *strcat16(char16_t *, const char16_t *) memcpyesque;
|
||||
wchar_t *wcscat(wchar_t *, const wchar_t *) memcpyesque;
|
||||
size_t strlcpy(char *, const char *, size_t);
|
||||
size_t strlcat(char *, const char *, size_t);
|
||||
char *strcpy(char *, const char *) memcpyesque;
|
||||
char16_t *strcpy16(char16_t *, const char16_t *) memcpyesque;
|
||||
wchar_t *wcscpy(wchar_t *, const wchar_t *) memcpyesque;
|
||||
char *strncat(char *, const char *, size_t) memcpyesque;
|
||||
char *strncpy(char *, const char *, size_t) memcpyesque;
|
||||
char *strtok(char *, const char *) paramsnonnull((2)) libcesque;
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/intrin/pcmpeqb.h"
|
||||
#include "libc/intrin/pmovmskb.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
/**
|
||||
|
|
|
@ -28,5 +28,5 @@
|
|||
* @return original dest
|
||||
*/
|
||||
char16_t *strcpy16(char16_t *dest, const char16_t *src) {
|
||||
return memcpy(dest, src, (strlen16(src) + 1) << 1);
|
||||
return memcpy(dest, src, (strlen16(src) + 1) * sizeof(char16_t));
|
||||
}
|
||||
|
|
|
@ -16,11 +16,16 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
int fputhex(int c, FILE *f) {
|
||||
return (fputc("0123456789ABCDEF"[(c / 16) & 0xF], f) >= 0 &&
|
||||
fputc("0123456789ABCDEF"[(c % 16) & 0xF], f) >= 0)
|
||||
? c
|
||||
: -1;
|
||||
/**
|
||||
* Appends 𝑠 to 𝑑.
|
||||
*
|
||||
* @param 𝑑 is a NUL-terminated 32-bit string
|
||||
* @param 𝑠 is a NUL-terminated 32-bit string
|
||||
* @return 𝑑
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
wchar_t *wcscat(wchar_t *d, const wchar_t *s) {
|
||||
return wcscpy(d + wcslen(d), s);
|
||||
}
|
|
@ -16,24 +16,18 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
int fgethex(FILE *f) {
|
||||
int o, t = -1;
|
||||
while (!((o = fgetc(f)) & ~0xFF)) {
|
||||
switch (t) {
|
||||
case -1:
|
||||
t = isxdigit(o) ? hextoint(o) : -1;
|
||||
break;
|
||||
default:
|
||||
if (isxdigit(o)) {
|
||||
return t * 16 + hextoint(o);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (t >= 0) return einval();
|
||||
return -1;
|
||||
/**
|
||||
* Copies NUL-terminated wide character string.
|
||||
*
|
||||
* 𝑑 and 𝑠 must not overlap unless 𝑑 ≤ 𝑠.
|
||||
*
|
||||
* @param 𝑑 is destination memory
|
||||
* @param 𝑠 is a NUL-terminated string
|
||||
* @return original dest
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
wchar_t *wcscpy(wchar_t *d, const wchar_t *s) {
|
||||
return memcpy(d, s, (wcslen(s) + 1) * sizeof(wchar_t));
|
||||
}
|
55
test/libc/calls/getcwd_test.c
Normal file
55
test/libc/calls/getcwd_test.c
Normal file
|
@ -0,0 +1,55 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ 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/calls/calls.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/runtime/gc.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
#include "libc/x/x.h"
|
||||
|
||||
char basedir[PATH_MAX];
|
||||
char testdir[PATH_MAX];
|
||||
|
||||
void SetUp(void) {
|
||||
getcwd(basedir, ARRAYLEN(basedir));
|
||||
sprintf(testdir, "o/tmp/%s.%d", program_invocation_short_name, getpid());
|
||||
makedirs(testdir, 0755);
|
||||
CHECK_NE(-1, chdir(testdir));
|
||||
}
|
||||
|
||||
void TearDown(void) {
|
||||
CHECK_NE(-1, chdir(basedir));
|
||||
CHECK_NE(-1, rmrf(testdir));
|
||||
}
|
||||
|
||||
TEST(getcwd, test) {
|
||||
char buf[PATH_MAX];
|
||||
EXPECT_NE(-1, mkdir("subdir", 0755));
|
||||
EXPECT_NE(-1, chdir("subdir"));
|
||||
EXPECT_STREQ("subdir", basename(getcwd(buf, ARRAYLEN(buf))));
|
||||
}
|
||||
|
||||
TEST(getcwd, testNullBuf_allocatesResult) {
|
||||
EXPECT_NE(-1, mkdir("subdir", 0755));
|
||||
EXPECT_NE(-1, chdir("subdir"));
|
||||
EXPECT_STREQ("subdir", basename(gc(getcwd(NULL, 0))));
|
||||
}
|
35
test/libc/str/strcasecmp_test.c
Normal file
35
test/libc/str/strcasecmp_test.c
Normal file
|
@ -0,0 +1,35 @@
|
|||
/*-*- 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 │
|
||||
│ │
|
||||
│ 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/str.h"
|
||||
#include "libc/testlib/ezbench.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
|
||||
TEST(strcasecmp, test) {
|
||||
EXPECT_EQ(0, strcasecmp("HELLO", "hello"));
|
||||
EXPECT_EQ(-17, strcasecmp("HELLO", "yello"));
|
||||
EXPECT_EQ(-17, strcasecmp("HELLO", "YELLO"));
|
||||
EXPECT_EQ(+17, strcasecmp("yello", "HELLO"));
|
||||
EXPECT_EQ(+17, strcasecmp("YELLO", "HELLO"));
|
||||
}
|
||||
|
||||
BENCH(strcasecmp, bench) {
|
||||
EZBENCH2("strcasecmp 16 eq", donothing,
|
||||
EXPROPRIATE(
|
||||
strcasecmp(VEIL("r", "abcdefghijklmnop"), "ABCDEFGHIJKLMNOP")));
|
||||
}
|
Loading…
Reference in a new issue