Files

567 lines
18 KiB
C

#ifndef VLIBC_STDLIB_H
#define VLIBC_STDLIB_H
/*
* vlibc — <stdlib.h>.
*
* This header is the shared home for the stdlib declarations; it currently
* holds only the memory-management family (todo 7). Later todos extend it
* in place: todo 11 adds the numeric conversions (atoi/strtol/strtod/...),
* todo 12 the pseudo-random and search/divide functions
* (rand/srand/qsort/bsearch/abs/div/...), and todo 13 the environment and
* multibyte helpers (getenv/setenv/mblen/mbtowc/...).
*
* Memory management functions, gated by the active compatibility profile
* (see include/vlibc/features.h). Levels are cumulative:
*
* Level 1 (onlyposix): ISO C core + POSIX base — malloc, free, calloc,
* realloc, aligned_alloc, posix_memalign.
* Level 2 (muslmimic): malloc_usable_size (BSD/musl).
*
* This header includes <vlibc/features.h> itself, so the gates below always
* see the configured VLIBC_LEVEL even when the caller included no vlibc
* header first, and <stddef.h> for size_t.
*/
#include <vlibc/features.h>
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
/* Level 1: memory management (always present). */
/*
* Allocate size bytes, 16-byte aligned. The memory is uninitialized.
* malloc(0) returns a unique minimum-size block (never NULL on success).
* NULL + errno ENOMEM on failure.
* malloc: the result does not alias any other pointer and has size bytes.
*/
__attribute__((malloc, alloc_size(1))) void *
malloc(size_t size);
/*
* Release the block at ptr, which must be NULL or a value returned by an
* earlier allocation in this family. free(NULL) is a no-op.
*/
void
free(void *ptr);
/*
* Allocate an array of nmemb elements of size bytes each, all bits zero.
* The product is overflow-checked: on overflow NULL + errno ENOMEM.
* calloc with a zero product returns a unique zeroed minimum-size block.
* malloc: the result does not alias any other pointer and has nmemb*size
* bytes.
*/
__attribute__((malloc, alloc_size(1, 2))) void *
calloc(size_t nmemb, size_t size);
/*
* Resize the block at ptr to size bytes, preserving the first min(old,
* size) bytes. realloc(NULL, size) behaves as malloc(size); realloc(ptr, 0)
* frees ptr and returns NULL. The old block is freed on success and left
* untouched on failure (NULL + errno ENOMEM).
* alloc_size(2): the result has size bytes.
*/
__attribute__((alloc_size(2))) void *
realloc(void *ptr, size_t size);
/*
* Allocate size bytes aligned to alignment. alignment must be a power of
* two that is a multiple of sizeof(void *), and size must be a multiple of
* alignment; a violation fails with NULL + errno EINVAL (a non-power-of-two
* alignment is undefined behavior in C23, so only well-formed arguments
* reach the allocator). size 0 returns NULL. The result is released with
* free.
* malloc + alloc_align(1): the result does not alias any other pointer and
* is aligned to alignment.
*/
__attribute__((malloc, alloc_size(2), alloc_align(1))) void *
aligned_alloc(size_t alignment, size_t size);
/*
* Allocate size bytes at address alignment and store the result in
* *memptr. alignment must be a power of two and a multiple of
* sizeof(void *). Returns 0 on success, EINVAL for a bad alignment, ENOMEM
* on allocation failure. Never sets errno itself, and never modifies
* *memptr on failure. size 0 returns a unique minimum-size block.
*/
__attribute__((access(write_only, 1))) int
posix_memalign(void **memptr, size_t alignment, size_t size);
#if VLIBC_LEVEL_GE(2)
/* Level 2 (muslmimic): BSD/musl extensions. */
/*
* Return the number of bytes actually available in the block at ptr,
* including any internal padding; at least as large as the requested size.
* ptr may be any block returned by the allocator family; NULL returns 0.
* pure: reads memory, no side effects.
*/
__attribute__((pure)) size_t
malloc_usable_size(void *ptr);
#endif /* VLIBC_LEVEL_GE(2) */
/* numeric conversions (todo 11) */
/*
* String-to-number conversions (C23 7.24.1). All are ISO C core / POSIX
* base and present in every profile.
*
* The ato* wrappers carry no error reporting: their behavior is undefined
* if the converted value cannot be represented (C23 7.24.1.1-2), so they
* read their input and nothing else — hence pure.
*
* The strto* functions report range errors through errno and store the
* scan position through endptr; both are real side effects, so they carry
* no intent attribute. errno behavior follows C23 7.24.1.4-5: ERANGE when
* the subject sequence is outside the representable range (the clamped
* maximum/minimum is returned); EINVAL when base is not 0 and not in
* [2, 36] (endptr left at nptr, 0 returned); endptr points at nptr when
* no subject sequence is present.
*/
/*
* Convert the initial decimal digits of nptr to int, discarding leading
* whitespace and an optional sign. Equivalent to (int)strtol(nptr, 0, 10).
* pure: reads memory, no side effects.
*/
__attribute__((pure)) int
atoi(const char *nptr);
/*
* As atoi, converted to long: strtol(nptr, 0, 10).
* pure: reads memory, no side effects.
*/
__attribute__((pure)) long
atol(const char *nptr);
/*
* As atoi, converted to long long: strtoll(nptr, 0, 10).
* pure: reads memory, no side effects.
*/
__attribute__((pure)) long long
atoll(const char *nptr);
/*
* As atoi, converted to double: strtod(nptr, 0).
* pure: reads memory, no side effects.
*/
__attribute__((pure)) double
atof(const char *nptr);
/*
* Convert the initial portion of nptr to long, stopping at the first
* character that is not part of the subject sequence and storing its
* position in *endptr (if endptr is not NULL). See the family comment for
* base, errno, and endptr semantics.
*/
long
strtol(const char *restrict nptr, char **restrict endptr, int base);
/*
* As strtol, converted to unsigned long. A subject sequence with a minus
* sign yields the negated value computed in the return type (modulo
* ULONG_MAX + 1) without a range error (C23 7.24.1.4p8).
*/
unsigned long
strtoul(const char *restrict nptr, char **restrict endptr, int base);
/*
* As strtol, converted to long long.
*/
long long
strtoll(const char *restrict nptr, char **restrict endptr, int base);
/*
* As strtol, converted to unsigned long long. Negative subject sequences
* wrap modulo ULLONG_MAX + 1 as for strtoul.
*/
unsigned long long
strtoull(const char *restrict nptr, char **restrict endptr, int base);
/*
* Convert the initial portion of nptr to float, double, or long double
* (C23 7.24.1.3): optional whitespace, optional sign, then either an
* "inf"/"infinity" or "nan"/"nan(n-char-sequence)" subject (case-
* insensitive), a hexadecimal floating subject ("0x1.8p1"), or a decimal
* floating subject with optional exponent. Overflow returns ±HUGE_VAL*
* with errno ERANGE; results too small to represent return a subnormal or
* zero value with errno ERANGE. no-conversion stores nptr in *endptr.
*/
double
strtod(const char *restrict nptr, char **restrict endptr);
float
strtof(const char *restrict nptr, char **restrict endptr);
long double
strtold(const char *restrict nptr, char **restrict endptr);
/* pseudo-random numbers, search, and integer arithmetic (todo 12) */
/*
* C23 7.22.2/7.22.5/7.22.6: rand/srand, qsort/bsearch, the abs family, and
* the div family are ISO C core and present in every profile. The abs and
* div functions compute a pure function of their arguments, so they are
* declared const (the compiler folds and eliminates the calls in static
* links; GCC's own builtin declarations of abs/labs/llabs are const, and
* the attribute here matches them). rand and srand carry state, and
* qsort/bsearch call a caller-supplied comparator, so none of those four
* carries an intent attribute.
*/
/*
* The largest value rand() returns: 2^31 - 1, the largest int.
*/
#define RAND_MAX 2147483647
/*
* Quotient/remainder pair from div/ldiv/lldiv: quot is the algebraic
* quotient truncated toward zero, rem the remainder of the same sign as
* the dividend, and quot*denom + rem == num.
*/
typedef struct
{
int quot;
int rem;
} div_t;
typedef struct
{
long quot;
long rem;
} ldiv_t;
typedef struct
{
long long quot;
long long rem;
} lldiv_t;
/*
* Absolute value of n. The most-negative value returns itself: the
* negation happens in the unsigned type, which wraps, so the result is
* never undefined behavior and errno is never set.
*/
__attribute__((const)) int
abs(int n);
__attribute__((const)) long
labs(long n);
__attribute__((const)) long long
llabs(long long n);
/*
* Quotient and remainder of num/denom, truncated toward zero.
*/
__attribute__((const)) div_t
div(int num, int denom);
__attribute__((const)) ldiv_t
ldiv(long num, long denom);
__attribute__((const)) lldiv_t
lldiv(long long num, long long denom);
/*
* Pseudo-random integer in [0, RAND_MAX], deterministic for a given
* srand seed.
*/
int
rand(void);
/*
* Seed the rand() sequence with seed.
*/
void
srand(unsigned int seed);
/*
* Sort the array of nmemb elements of size bytes at base into ascending
* order according to compar (C23 7.22.5.2). compar receives two pointers
* to distinct elements and returns negative/zero/positive. The sort is
* not stable.
*/
void
qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *));
/*
* Binary-search the array of nmemb sorted elements of size bytes at base
* for *key, calling compar(key, element) (C23 7.22.5.1). Returns a
* pointer to the matching element, or NULL when there is none.
*/
void *
bsearch(const void *key, const void *base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *));
#if VLIBC_LEVEL_GE(2)
/* Level 2 (muslmimic): XSI and obsolescent extensions. */
/*
* Reentrant rand: the state lives in the caller's *seedp, which is
* updated on every call, so the sequence is independent of rand()'s own
* global state.
*/
int
rand_r(unsigned int *seedp);
/*
* random/srandom family (XSI): a 31-bit pseudo-random sequence in
* [0, 2^31). initstate installs state (size bytes, at least
* sizeof(long)) as the current state buffer, seeds it, and returns the
* previous buffer; setstate installs the buffer and returns the previous
* one. srandom reseeds the current buffer.
*/
long
random(void);
void
srandom(unsigned int seed);
char *
initstate(unsigned int seed, char *state, size_t size);
char *
setstate(char *state);
/*
* drand48 family (XSI): a 48-bit linear congruential sequence carried in
* three unsigned shorts, least-significant first. drand48/erand48 return
* the current value divided by 2^48 as a double in [0, 1); lrand48/
* nrand48 return the high 31 bits; mrand48/jrand48 the high 32 bits
* sign-extended. The erand48/nrand48/jrand48 forms step the caller's
* xsubi in place; srand48/seed48/lcong48 manage the shared state and the
* multiplier/addend.
*/
double
drand48(void);
double
erand48(unsigned short xsubi[3]);
long
lrand48(void);
long
nrand48(unsigned short xsubi[3]);
long
mrand48(void);
long
jrand48(unsigned short xsubi[3]);
void
srand48(long seedval);
unsigned short *
seed48(unsigned short seed16v[3]);
void
lcong48(unsigned short param[7]);
#endif /* VLIBC_LEVEL_GE(2) */
/* environment, multibyte characters, and temporary files (todo 13) */
/*
* getenv/setenv/unsetenv (POSIX base), the C-locale multibyte conversions
* (C23 7.24.7), and mkstemp/mkdtemp are level 1. The XSI/BSD extras —
* putenv, clearenv, mktemp, the PTY helpers, and getsubopt — are level 2.
*
* None of these functions carries an intent attribute. getenv and the
* environment mutators all read or write the shared global environ, so
* pure/const would let the compiler hoist a stale getenv result across a
* setenv call. The multibyte conversions are locale-stateful in general,
* the temporary-file functions create filesystem entries, and ptsname
* writes a shared static buffer — none of them is side-effect-free.
*/
/*
* The process environment: a NULL-terminated array of "name=value"
* strings. The array is installed by the startup code before main; the
* functions below mutate it (setenv/unsetenv copy strings into malloc'd
* storage). Reassigning environ directly is permitted by POSIX, but
* calling setenv/unsetenv/putenv/clearenv afterwards is undefined, as it
* is everywhere (the array is then no longer guaranteed to be owned by
* the library).
*/
extern char **environ;
/*
* Return a pointer to the value part (the bytes after '=') of the
* environment entry whose name matches name, or NULL when the variable
* is not set. The pointer is valid until the next setenv, unsetenv,
* putenv, or clearenv call. No intent attribute: the result depends on
* the mutable global environ.
*/
char *
getenv(const char *name);
/*
* Set name to value. A copy of "name=value" is made, so the caller may
* reuse or free its buffers once the call returns. With overwrite
* nonzero an existing entry is replaced; with overwrite zero an existing
* entry is left unchanged and 0 is returned. Returns -1 with errno
* EINVAL when name is NULL, empty, or contains '=', and -1 with errno
* ENOMEM on allocation failure. A NULL value is treated as the empty
* string.
*/
int
setenv(const char *name, const char *value, int overwrite);
/*
* Remove every entry whose name is name, compacting the array. Returns
* -1 with errno EINVAL when name is NULL, empty, or contains '='.
*/
int
unsetenv(const char *name);
/*
* C-locale multibyte conversions (C23 7.24.7). Only the "C" locale
* exists today (locale support is a later todo), where every multibyte
* character is a single byte: byte c corresponds to the wide character
* (unsigned char)c. The encoding is therefore stateless — the s == NULL
* and NULL-destination forms all report "state-independent" — and no
* mbstate_t variant is needed. mbtowc never fails in this locale (every
* byte, including 0x80..0xFF, is a valid character); wctomb fails with
* -1 + errno EILSEQ for any wchar_t outside 0..255.
*/
int
mblen(const char *s, size_t n);
int
mbtowc(wchar_t *restrict pwc, const char *restrict s, size_t n);
int
wctomb(char *s, wchar_t wc);
size_t
mbstowcs(wchar_t *restrict pwcs, const char *restrict s, size_t n);
size_t
wcstombs(char *restrict s, const wchar_t *restrict pwcs, size_t n);
/*
* Temporary files and directories. mkstemp replaces the trailing
* "XXXXXX" of the template with random characters, creates the file
* with mode 0600, and returns an open file descriptor (-1 with errno
* EINVAL when the template has no "XXXXXX" suffix). mkdtemp does the
* same replacement, creates a directory with mode 0700, and returns the
* template (NULL on failure). The parameter is unnamed in these
* declarations because POSIX's `template` is a C++ keyword and this
* header is compiled by C++ consumers too.
*/
int
mkstemp(char *);
char *
mkdtemp(char *);
/* process control (todo 20) */
/*
* Pass string to the command language interpreter: "sh -c string".
* Returns the shell's wait status (e.g. 768 for "exit 3"), 1 when
* string is NULL (a shell is always available), or -1 with errno set
* when the child cannot be created or reaped. During the run, SIGCHLD
* is blocked and SIGINT/SIGQUIT are ignored in the caller, as POSIX
* requires.
*/
int
system(const char *string);
#if VLIBC_LEVEL_GE(2)
/* Level 2 (muslmimic): XSI and BSD environment extras. */
/*
* Add string — a "name=value" pair in CALLER-OWNED storage — to the
* environment: the caller's buffer becomes part of the environment and
* must remain valid for the life of the process. An existing variable of
* the same name is replaced (the old pointer is dropped); a string
* without '=' removes the variable instead (glibc/musl behavior).
* Returns 0, or -1 with errno ENOMEM.
*/
int
putenv(char *string);
/*
* Empty the environment, leaving environ as a fresh valid empty array
* (never NULL) so later setenv calls keep working. The previous array
* and its entries are deliberately not freed — entries may be putenv'd
* caller storage or initial-stack strings. Returns 0, or -1 with errno
* ENOMEM.
*/
int
clearenv(void);
/*
* Obsolescent mkstemp without the file: fills in the trailing "XXXXXX"
* and returns the template, creating nothing. The name is not guaranteed
* unique — nothing exists to race on. NULL with errno EINVAL when the
* template has no "XXXXXX" suffix.
*/
char *
mktemp(char *);
/*
* XSI PTY helpers. posix_openpt opens the master side of a
* pseudo-terminal via /dev/ptmx (flags, plus O_NOCTTY, are passed to
* open) and returns the fd. grantpt returns 0 without doing anything:
* modern kernels grant the slave when the master is opened. unlockpt
* releases the slave-side lock. ptsname formats the slave path
* "/dev/pts/N" into a shared static buffer — the result is valid until
* the next ptsname call and is not thread-safe.
*/
int
posix_openpt(int flags);
char *
ptsname(int fd);
int
grantpt(int fd);
int
unlockpt(int fd);
/*
* Parse one comma-separated suboption out of *optionp (POSIX XSI). On
* success the index of the matching token is returned and *valuep points
* to the "=value" part (or is NULL when the suboption has no '='); for
* an unrecognized suboption -1 is returned and *valuep points to the
* whole suboption string; at the end of the list -1 is returned and
* *valuep is NULL. *optionp always advances past the comma, which is
* overwritten with NUL (the string is modified in place).
*/
int
getsubopt(char **optionp, char *const *tokens, char **valuep);
#endif /* VLIBC_LEVEL_GE(2) */
#if VLIBC_LEVEL_GE(2)
/*
* Resolve path to an absolute, NUL-terminated canonical pathname with no
* symbolic links, "." or ".." components (todo 38). resolved_path may be
* NULL, in which case the canonical path is returned in a malloc'd
* buffer the caller must free; otherwise it must hold at least PATH_MAX
* bytes. Returns resolved_path (or the malloc'd buffer), or NULL with
* errno set. XSI.
*/
char *
realpath(const char *restrict path, char *restrict resolved_path);
#endif /* VLIBC_LEVEL_GE(2) */
#ifdef __cplusplus
}
#endif
#endif /* VLIBC_STDLIB_H */