#ifndef _STDLIB_H
#define _STDLIB_H

#include <bits/macros.h>
#include <limits.h>
#include <stddef.h>

#define EXIT_SUCCESS 0 // Value to use when calling exit() to represent successful execution.
#define EXIT_FAILURE 1 // Value to use when calling exit() to represent failed execution.

#define RAND_MAX INT_MAX // Maximum number returned by rand().

// Return type for an integer division.
typedef struct
{
    int quot;
    int rem;
} div_t;

// Return type for a long integer division.
typedef struct
{
    long quot;
    long rem;
} ldiv_t;

// Return type for a long integer division.
typedef struct
{
    long long quot;
    long long rem;
} lldiv_t;

#ifdef __cplusplus
extern "C"
{
#endif

    /* Aborts the program. */
    __lc_noreturn void abort(void);

    /* Normally exits the program with the specified status code. */
    __lc_noreturn void exit(int status);

    /* Abnormally exits the program with the specified status code. */
    __lc_noreturn void _Exit(int status);

    /* Registers a handler function to be run at normal program termination. */
    int atexit(void (*handler)(void));

    /* Returns an integer (of type int) parsed from the string str. */
    int atoi(const char* str);

    /* Returns an integer (of type long) parsed from the string str. */
    long atol(const char* str);

    /* Returns an integer (of type long long) parsed from the string str. */
    long long atoll(const char* str);

    /* Returns an integer (of type unsigned long) parsed from the string str. */
    unsigned long strtoul(const char* str, char** endptr, int base);

    /* Returns an integer (of type long) parsed from the string str. */
    long strtol(const char* str, char** endptr, int base);

    /* Not implemented. */
    char* getenv(const char*);

    /* Allocates n bytes of memory and returns a pointer to it. This memory should be freed by calling free() when it is
     * not in use anymore. */
    void* malloc(size_t n);

    /* Allocates enough bytes of memory for an array containing nmemb items of size n and returns a pointer to it. This
     * memory should be freed by calling free() when it is not in use anymore. */
    void* calloc(size_t nmemb, size_t n);

    /* Resizes memory allocated by malloc() or calloc() to n bytes. Returns a pointer to the new resized region of
     * memory, which should be used instead of the old one. This memory should be freed by calling free() when it is not
     * in use anymore. */
    void* realloc(void* ptr, size_t n);

    /* Frees a pointer to memory allocated by malloc(), calloc() or realloc(). Accessing the contents of ptr afterwards
     * is undefined behavior. */
    void free(void* ptr);

    /* Returns a random number. */
    int rand(void);

    /* Seeds the random number generator with the specified seed. */
    void srand(unsigned int seed);

    /* Returns the absolute value of an integer. */
    int abs(int val);

    /* Returns the absolute value of an integer. */
    long labs(long val);

    /* Returns the absolute value of an integer. */
    long long llabs(long long val);

    /* Returns the result of dividing a by b. */
    div_t div(int a, int b);

    /* Returns the result of dividing a by b. */
    ldiv_t ldiv(long a, long b);

    /* Returns the result of dividing a by b. */
    lldiv_t lldiv(long long a, long long b);

    void qsort(void*, size_t, size_t, int (*)(const void*, const void*)); // Not implemented.

#ifdef __cplusplus
}
#endif

#endif