#ifndef _STDIO_H
#define _STDIO_H

#include <stdarg.h>
#include <stddef.h>

#include <bits/seek.h>

#define FOPEN_MAX 32

typedef struct
{
    int f_fd;
    int f_eof;
    int f_err;
} FILE;

extern FILE* stderr;
extern FILE* stdout;
#define stdout stdout
#define stderr stderr

typedef struct
{
    long f_offset;
} fpos_t;

#ifdef __cplusplus
extern "C"
{
#endif

    /* Closes the file handle stream. */
    int fclose(FILE* stream);

    /* Does not do anything for now, since buffered IO is not implemented yet. */
    int fflush(FILE* stream);

    /* Opens the file specified by pathname. Returns the file handle on success, or NULL on error. */
    FILE* fopen(const char* pathname, const char* mode);

    /* Returns a new file associated with the file descriptor fd. */
    FILE* fdopen(int fd, const char* mode);

    /* Returns the file descriptor associated with the file stream. */
    int fileno(FILE* stream);

    /* Writes formatted output according to the string format to the file stream. */
    int fprintf(FILE* stream, const char* format, ...);

    /* Reads nmemb items of size size from the file stream into buf. */
    size_t fread(void* buf, size_t size, size_t nmemb, FILE* stream);

    /* Moves stream's read/write offset by offset, depending on whence. */
    int fseek(FILE* stream, long offset, int whence);

    /* Moves stream's read/write offset to the offset stored in the pos structure. */
    int fsetpos(FILE* stream, const fpos_t* pos);

    /* Returns the current offset for stream. */
    long ftell(FILE* stream);

    /* Stores the current offset for stream in the pos structure. */
    int fgetpos(FILE* stream, fpos_t* pos);

    /* Rewinds stream's offset to start of file. */
    void rewind(FILE* stream);

    /* Writes nmemb items of size size from buf into the file stream. */
    size_t fwrite(const void* buf, size_t size, size_t nmemb, FILE* stream);

    /* Returns nonzero if the error flag in stream was set. */
    int ferror(FILE* stream);

    /* Returns nonzero if the end-of-file flag in stream was set. */
    int feof(FILE* stream);

    /* Clears the error and end-of-file flags from stream. */
    void clearerr(FILE* stream);

    void setbuf(FILE*, char*); // Not implemented.

    /* Writes formatted output according to the string format to the file stream. */
    int vfprintf(FILE* stream, const char* format, va_list ap);

    /* Writes formatted output according to the string format to standard output. */
    int printf(const char* format, ...);

    /* Writes formatted output according to the string format to standard output. */
    int vprintf(const char* format, va_list ap);

    /* Writes formatted output according to the string format to the string str. This function is unsafe, use snprintf
     * instead. */
    int sprintf(char* str, const char* format, ...);

    /* Writes at most max bytes of formatted output according to the string format to the string str.*/
    int snprintf(char* str, size_t max, const char* format, ...);

    /* Writes formatted output according to the string format to the string str. This function is unsafe, use vsnprintf
     * instead. */
    int vsprintf(char* str, const char* format, va_list ap);

    /* Writes at most max bytes of formatted output according to the string format to the string str. */
    int vsnprintf(char* str, size_t max, const char* format, va_list ap);

    /* Writes the string str followed by a trailing newline to stdout. */
    int puts(const char* str);

    /* Writes the string str to the file stream. */
    int fputs(const char* str, FILE* stream);

    /* Writes the character c to the file stream. */
    int fputc(int c, FILE* stream);

    /* Writes the character c to the file stream. */
    int putc(int c, FILE* stream);

    /* Writes the character c to standard output. */
    int putchar(int c);

    /* Prints a message to standard error consisting of the string str followed by a colon and the string representation
     * of the last error encountered during a call to a system or library function. */
    void perror(const char* str);

#ifdef __cplusplus
}
#endif

#endif