feat(stdlib): environment and multibyte helpers

This commit is contained in:
2026-09-04 22:56:00 -04:00
parent bff8fe9c86
commit b53ccaa1e8
7 changed files with 1317 additions and 0 deletions
+164
View File
@@ -367,6 +367,170 @@ 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 *);
#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) */
#ifdef __cplusplus
}
#endif