feat: libc - add strndup, scandir, alphasort, usleep, ftruncate, M_PI constants
Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_018Ae69wJS7sueQMUwNxV3nX
This commit is contained in:
@@ -12,4 +12,4 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define MONTAUK_BUILD_NUMBER 90
|
#define MONTAUK_BUILD_NUMBER 91
|
||||||
|
|||||||
@@ -29,6 +29,11 @@ struct dirent *readdir(DIR *dirp);
|
|||||||
int closedir(DIR *dirp);
|
int closedir(DIR *dirp);
|
||||||
void rewinddir(DIR *dirp);
|
void rewinddir(DIR *dirp);
|
||||||
|
|
||||||
|
int scandir(const char *dirp, struct dirent ***namelist,
|
||||||
|
int (*filter)(const struct dirent *),
|
||||||
|
int (*compar)(const struct dirent **, const struct dirent **));
|
||||||
|
int alphasort(const struct dirent **a, const struct dirent **b);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -11,6 +11,24 @@ extern "C" {
|
|||||||
#define INFINITY __builtin_inff()
|
#define INFINITY __builtin_inff()
|
||||||
#define NAN __builtin_nanf("")
|
#define NAN __builtin_nanf("")
|
||||||
|
|
||||||
|
/*
|
||||||
|
* X/Open math constants. Not in ISO C, but ported code assumes them freely
|
||||||
|
* (NetSurf's about:chart uses M_PI and M_PI_2).
|
||||||
|
*/
|
||||||
|
#define M_E 2.7182818284590452354
|
||||||
|
#define M_LOG2E 1.4426950408889634074
|
||||||
|
#define M_LOG10E 0.43429448190325182765
|
||||||
|
#define M_LN2 0.69314718055994530942
|
||||||
|
#define M_LN10 2.30258509299404568402
|
||||||
|
#define M_PI 3.14159265358979323846
|
||||||
|
#define M_PI_2 1.57079632679489661923
|
||||||
|
#define M_PI_4 0.78539816339744830962
|
||||||
|
#define M_1_PI 0.31830988618379067154
|
||||||
|
#define M_2_PI 0.63661977236758134308
|
||||||
|
#define M_2_SQRTPI 1.12837916709551257390
|
||||||
|
#define M_SQRT2 1.41421356237309504880
|
||||||
|
#define M_SQRT1_2 0.70710678118654752440
|
||||||
|
|
||||||
/* C99 floating-point classification. */
|
/* C99 floating-point classification. */
|
||||||
#define FP_NAN 0
|
#define FP_NAN 0
|
||||||
#define FP_INFINITE 1
|
#define FP_INFINITE 1
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ char *strncpy(char *dest, const char *src, size_t n);
|
|||||||
char *strcat(char *dest, const char *src);
|
char *strcat(char *dest, const char *src);
|
||||||
char *strncat(char *dest, const char *src, size_t n);
|
char *strncat(char *dest, const char *src, size_t n);
|
||||||
char *strdup(const char *s);
|
char *strdup(const char *s);
|
||||||
|
char *strndup(const char *s, size_t n);
|
||||||
char *strchr(const char *s, int c);
|
char *strchr(const char *s, int c);
|
||||||
char *strrchr(const char *s, int c);
|
char *strrchr(const char *s, int c);
|
||||||
char *strpbrk(const char *s, const char *accept);
|
char *strpbrk(const char *s, const char *accept);
|
||||||
|
|||||||
@@ -61,6 +61,8 @@ long sysconf(int name);
|
|||||||
extern char **environ;
|
extern char **environ;
|
||||||
|
|
||||||
unsigned int sleep(unsigned int seconds);
|
unsigned int sleep(unsigned int seconds);
|
||||||
|
int usleep(unsigned long usec);
|
||||||
|
int ftruncate(int fd, long length);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -571,6 +571,18 @@ char *strdup(const char *s) {
|
|||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *strndup(const char *s, size_t n) {
|
||||||
|
size_t len = 0;
|
||||||
|
char *d;
|
||||||
|
if (s == NULL) return NULL;
|
||||||
|
while (len < n && s[len] != '\0') len++;
|
||||||
|
d = (char *)malloc(len + 1);
|
||||||
|
if (d == NULL) return NULL;
|
||||||
|
memcpy(d, s, len);
|
||||||
|
d[len] = '\0';
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
const char *strerror(int errnum) {
|
const char *strerror(int errnum) {
|
||||||
switch (errnum) {
|
switch (errnum) {
|
||||||
case 0: return "success";
|
case 0: return "success";
|
||||||
@@ -2047,6 +2059,49 @@ int write(int fd, const void *buf, size_t count) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ftruncate: EXTEND ONLY.
|
||||||
|
*
|
||||||
|
* The kernel has no truncate syscall, so growth is emulated by writing zeros
|
||||||
|
* at the tail. Shrinking cannot be emulated and fails with ENOSYS rather than
|
||||||
|
* silently reporting success -- a caller that believes a file shrank when it
|
||||||
|
* did not is worse off than one told it is unsupported.
|
||||||
|
*/
|
||||||
|
int ftruncate(int fd, long length) {
|
||||||
|
unsigned long size;
|
||||||
|
static const unsigned char zeros[512] = { 0 };
|
||||||
|
|
||||||
|
if (fd < 0 || length < 0) {
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
size = (unsigned long)_zos_syscall1(SYS_GETSIZE, (long)fd);
|
||||||
|
|
||||||
|
if ((unsigned long)length == size)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if ((unsigned long)length < size) {
|
||||||
|
errno = ENOSYS; /* no kernel truncate; cannot shrink */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (size < (unsigned long)length) {
|
||||||
|
unsigned long chunk = (unsigned long)length - size;
|
||||||
|
int written;
|
||||||
|
if (chunk > sizeof(zeros)) chunk = sizeof(zeros);
|
||||||
|
written = (int)_zos_syscall4(SYS_FWRITE, (long)fd, (long)zeros,
|
||||||
|
(long)size, (long)chunk);
|
||||||
|
if (written <= 0) {
|
||||||
|
errno = EIO;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
size += (unsigned long)written;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Positioned I/O. SYS_READ/SYS_FWRITE already take an explicit file position,
|
* Positioned I/O. SYS_READ/SYS_FWRITE already take an explicit file position,
|
||||||
* so these pass the caller's offset straight through and never consult or
|
* so these pass the caller's offset straight through and never consult or
|
||||||
@@ -2273,6 +2328,68 @@ struct dirent *readdir(DIR *dirp) {
|
|||||||
return &dirp->entry;
|
return &dirp->entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* scandir/alphasort, built on opendir/readdir. The array and every entry are
|
||||||
|
* malloc'd; the caller frees each entry then the array, as POSIX requires.
|
||||||
|
*/
|
||||||
|
int alphasort(const struct dirent **a, const struct dirent **b) {
|
||||||
|
return strcmp((*a)->d_name, (*b)->d_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
int scandir(const char *dirp, struct dirent ***namelist,
|
||||||
|
int (*filter)(const struct dirent *),
|
||||||
|
int (*compar)(const struct dirent **, const struct dirent **)) {
|
||||||
|
DIR *d;
|
||||||
|
struct dirent *ent;
|
||||||
|
struct dirent **list = NULL;
|
||||||
|
size_t count = 0, cap = 0;
|
||||||
|
|
||||||
|
if (dirp == NULL || namelist == NULL) {
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
d = opendir(dirp);
|
||||||
|
if (d == NULL) return -1;
|
||||||
|
|
||||||
|
while ((ent = readdir(d)) != NULL) {
|
||||||
|
struct dirent *copy;
|
||||||
|
|
||||||
|
if (filter != NULL && filter(ent) == 0) continue;
|
||||||
|
|
||||||
|
if (count == cap) {
|
||||||
|
size_t newcap = (cap == 0) ? 16 : cap * 2;
|
||||||
|
struct dirent **grown =
|
||||||
|
(struct dirent **)realloc(list, newcap * sizeof(*list));
|
||||||
|
if (grown == NULL) goto nomem;
|
||||||
|
list = grown;
|
||||||
|
cap = newcap;
|
||||||
|
}
|
||||||
|
|
||||||
|
copy = (struct dirent *)malloc(sizeof(*copy));
|
||||||
|
if (copy == NULL) goto nomem;
|
||||||
|
*copy = *ent;
|
||||||
|
list[count++] = copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
closedir(d);
|
||||||
|
|
||||||
|
if (compar != NULL && count > 1) {
|
||||||
|
qsort(list, count, sizeof(*list),
|
||||||
|
(int (*)(const void *, const void *))compar);
|
||||||
|
}
|
||||||
|
|
||||||
|
*namelist = list;
|
||||||
|
return (int)count;
|
||||||
|
|
||||||
|
nomem:
|
||||||
|
while (count > 0) free(list[--count]);
|
||||||
|
free(list);
|
||||||
|
closedir(d);
|
||||||
|
errno = ENOMEM;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
int closedir(DIR *dirp) {
|
int closedir(DIR *dirp) {
|
||||||
if (dirp == NULL) {
|
if (dirp == NULL) {
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
@@ -3037,6 +3154,19 @@ unsigned int sleep(unsigned int seconds) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sub-second sleeps. The kernel only offers millisecond granularity, so
|
||||||
|
* anything finer rounds UP to 1ms rather than to zero -- a caller asking for a
|
||||||
|
* short delay wants to yield, not to spin.
|
||||||
|
*/
|
||||||
|
int usleep(unsigned long usec) {
|
||||||
|
unsigned long ms = usec / 1000UL;
|
||||||
|
if (ms == 0 && usec != 0)
|
||||||
|
ms = 1;
|
||||||
|
_zos_syscall1(SYS_SLEEP_MS, (long)ms);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* ========================================================================
|
/* ========================================================================
|
||||||
math.h: modf and C99 float variants (wrappers over the double
|
math.h: modf and C99 float variants (wrappers over the double
|
||||||
implementations; assumed present by hosted libstdc++)
|
implementations; assumed present by hosted libstdc++)
|
||||||
|
|||||||
Binary file not shown.
Reference in New Issue
Block a user