#ifndef _STDLIB_H
#define _STDLIB_H

#ifdef __cplusplus
extern "C" {
#endif

typedef unsigned long size_t;

#ifndef NULL
# define NULL ((void *)0)
#endif

void  *malloc(size_t n);
void  *calloc(size_t nmemb, size_t size);
void  *realloc(void *ptr, size_t n);
void   free(void *p);
// C11 aligned allocation.  `alignment` must be a power of two; `size`
// must be a multiple of `alignment`.  Free with `aligned_free` (not
// plain `free`) — the returned pointer is offset from the malloc-block
// base by an alignment-pad and the original base is stashed just below.
void  *aligned_alloc(size_t alignment, size_t size);
void   aligned_free(void *p);
int    posix_memalign(void **memptr, size_t alignment, size_t size);

int    abs(int n);
long   labs(long n);
long long llabs(long long n);
int    atoi(const char *s);
long   atol(const char *s);
long long atoll(const char *s);
double atof(const char *s);

typedef struct { int       quot, rem; } div_t;
typedef struct { long      quot, rem; } ldiv_t;
typedef struct { long long quot, rem; } lldiv_t;
div_t   div  (int       n, int       d);
ldiv_t  ldiv (long      n, long      d);
lldiv_t lldiv(long long n, long long d);

long           strtol  (const char *nptr, char **endptr, int base);
unsigned long  strtoul (const char *nptr, char **endptr, int base);
long long      strtoll (const char *nptr, char **endptr, int base);
unsigned long long strtoull(const char *nptr, char **endptr, int base);
double         strtod  (const char *nptr, char **endptr);
float          strtof  (const char *nptr, char **endptr);

typedef int (*__cmp_fn)(const void *, const void *);
void   qsort  (void *base, size_t nmemb, size_t size, __cmp_fn cmp);
void  *bsearch(const void *key, const void *base, size_t nmemb,
               size_t size, __cmp_fn cmp);

void   exit(int code) __attribute__((noreturn));
void   _Exit(int code) __attribute__((noreturn));
void   abort(void)    __attribute__((noreturn));
// C11 quick_exit / at_quick_exit — like exit/atexit but invoke a
// separate handler chain.  No file flushing, no atexit handlers.
void   quick_exit(int code) __attribute__((noreturn));

typedef void (*__atexit_fn)(void);
int    atexit(__atexit_fn fn);
int    at_quick_exit(__atexit_fn fn);

// Environment: bare GS/OS has none, so libc.c's weak `getenv` returns NULL and
// `system` returns 0.  Under GNO (libcGno.o linked) getenv/setenv/putenv/
// unsetenv are backed by the kernel shell-variable table.  `environ` stays NULL
// in that thin port -- use the accessors, not environ[] directly.
char  *getenv(const char *name);
int    setenv(const char *name, const char *value, int overwrite);
int    unsetenv(const char *name);
int    putenv(const char *str);
extern char **environ;
int    system(const char *cmd);

#define EXIT_SUCCESS 0
#define EXIT_FAILURE 1

#define RAND_MAX 0x7FFF
int    rand(void);
void   srand(unsigned int seed);

// POSIX file helpers (Phase 3.3 of docs/GAP_CLOSURE_PLAN.md).  These
// route through the GS/OS dispatcher when `__gsosAvailable()` is 1;
// without a real dispatcher mkstemp() degrades gracefully (mfs paths
// keep working) and realpath() can still canonicalize already-absolute
// strings.
char *realpath(const char *path, char *resolved);
int   mkstemp(char *templateStr);

#ifdef __cplusplus
}
#endif

#endif
