#pragma once

#ifdef __cplusplus
extern "C" {
#endif

#include <features.h>
#include <bits/null.h>

#define __NEED_FILE
#define __NEED___isoc_va_list
#define __NEED_size_t
#define __NEED_wchar_t
#define __NEED_wint_t
#define __NEED_mbstate_t

#if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) || defined(_XOPEN_SOURCE) || \
    defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
#define __NEED_va_list
#endif

#if defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
#define __NEED_wctype_t
#endif

#include <bits/alltypes.h>

#ifndef WCHAR_MAX
#define WCHAR_MAX __WCHAR_MAX__
#endif

#ifndef WCHAR_MIN
#if defined(__WCHAR_MIN__)
#define WCHAR_MIN __WCHAR_MIN__
#else // defined(__WCHAR_MIN__)
#if defined(__WCHAR_UNSIGNED__)
#define WCHAR_MIN (L'\0' + 0)
#else
#define WCHAR_MIN (-WCHAR_MAX - 1)
#endif // defined (__WCHAR_UNSIGNED)
#endif // defined(__WCHAR_MIN__)
#endif

#undef WEOF
#define WEOF 0xffffffffU

wchar_t* wcscpy(wchar_t* __restrict, const wchar_t* __restrict);
wchar_t* wcsncpy(wchar_t* __restrict, const wchar_t* __restrict, size_t);

wchar_t* wcscat(wchar_t* __restrict, const wchar_t* __restrict);
wchar_t* wcsncat(wchar_t* __restrict, const wchar_t* __restrict, size_t);

int wcscmp(const wchar_t*, const wchar_t*);
int wcsncmp(const wchar_t*, const wchar_t*, size_t);

int wcscoll(const wchar_t*, const wchar_t*);
size_t wcsxfrm(wchar_t* __restrict, const wchar_t* __restrict, size_t n);

wchar_t* wcschr(const wchar_t*, wchar_t);
wchar_t* wcsrchr(const wchar_t*, wchar_t);

size_t wcscspn(const wchar_t*, const wchar_t*);
size_t wcsspn(const wchar_t*, const wchar_t*);
wchar_t* wcspbrk(const wchar_t*, const wchar_t*);

wchar_t* wcstok(wchar_t* __restrict, const wchar_t* __restrict, wchar_t** __restrict);

size_t wcslen(const wchar_t*);

wchar_t* wcsstr(const wchar_t* __restrict, const wchar_t* __restrict);
wchar_t* wcswcs(const wchar_t*, const wchar_t*);

wchar_t* wmemchr(const wchar_t*, wchar_t, size_t);
int wmemcmp(const wchar_t*, const wchar_t*, size_t);
wchar_t* wmemcpy(wchar_t* __restrict, const wchar_t* __restrict, size_t);
wchar_t* wmemmove(wchar_t*, const wchar_t*, size_t);
wchar_t* wmemset(wchar_t*, wchar_t, size_t);

wint_t btowc(int);
int wctob(wint_t);

int mbsinit(const mbstate_t*);
size_t mbrtowc(wchar_t* __restrict, const char* __restrict, size_t, mbstate_t* __restrict);
size_t wcrtomb(char* __restrict, wchar_t, mbstate_t* __restrict);

size_t mbrlen(const char* __restrict, size_t, mbstate_t* __restrict);

size_t mbsrtowcs(wchar_t* __restrict, const char** __restrict, size_t, mbstate_t* __restrict);
size_t wcsrtombs(char* __restrict, const wchar_t** __restrict, size_t, mbstate_t* __restrict);

float wcstof(const wchar_t* __restrict, wchar_t** __restrict);
double wcstod(const wchar_t* __restrict, wchar_t** __restrict);
long double wcstold(const wchar_t* __restrict, wchar_t** __restrict);

long wcstol(const wchar_t* __restrict, wchar_t** __restrict, int);
unsigned long wcstoul(const wchar_t* __restrict, wchar_t** __restrict, int);

long long wcstoll(const wchar_t* __restrict, wchar_t** __restrict, int);
unsigned long long wcstoull(const wchar_t* __restrict, wchar_t** __restrict, int);

int fwide(FILE*, int);

int wprintf(const wchar_t* __restrict, ...);
int fwprintf(FILE* __restrict, const wchar_t* __restrict, ...);
int swprintf(wchar_t* __restrict, size_t, const wchar_t* __restrict, ...);

int vwprintf(const wchar_t* __restrict, __isoc_va_list);
int vfwprintf(FILE* __restrict, const wchar_t* __restrict, __isoc_va_list);
int vswprintf(wchar_t* __restrict, size_t, const wchar_t* __restrict, __isoc_va_list);

int wscanf(const wchar_t* __restrict, ...);
int fwscanf(FILE* __restrict, const wchar_t* __restrict, ...);
int swscanf(const wchar_t* __restrict, const wchar_t* __restrict, ...);

int vwscanf(const wchar_t* __restrict, __isoc_va_list);
int vfwscanf(FILE* __restrict, const wchar_t* __restrict, __isoc_va_list);
int vswscanf(const wchar_t* __restrict, const wchar_t* __restrict, __isoc_va_list);

wint_t fgetwc(FILE*);
wint_t getwc(FILE*);
wint_t getwchar(void);

wint_t fputwc(wchar_t, FILE*);
wint_t putwc(wchar_t, FILE*);
wint_t putwchar(wchar_t);

wchar_t* fgetws(wchar_t* __restrict, int, FILE* __restrict);
int fputws(const wchar_t* __restrict, FILE* __restrict);

wint_t ungetwc(wint_t, FILE*);

struct tm;
size_t wcsftime(wchar_t* __restrict, size_t, const wchar_t* __restrict,
                const struct tm* __restrict);

#undef iswdigit

#if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) || defined(_XOPEN_SOURCE) || \
    defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
FILE* open_wmemstream(wchar_t**, size_t*);
size_t mbsnrtowcs(wchar_t* __restrict, const char** __restrict, size_t, size_t,
                  mbstate_t* __restrict);
size_t wcsnrtombs(char* __restrict, const wchar_t** __restrict, size_t, size_t,
                  mbstate_t* __restrict);
wchar_t* wcsdup(const wchar_t*);
size_t wcsnlen(const wchar_t*, size_t);
wchar_t* wcpcpy(wchar_t* __restrict, const wchar_t* __restrict);
wchar_t* wcpncpy(wchar_t* __restrict, const wchar_t* __restrict, size_t);
int wcscasecmp(const wchar_t*, const wchar_t*);
int wcsncasecmp(const wchar_t*, const wchar_t*, size_t);
#endif

#if defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
int wcwidth(wchar_t);
int wcswidth(const wchar_t*, size_t);
int iswalnum(wint_t);
int iswalpha(wint_t);
int iswblank(wint_t);
int iswcntrl(wint_t);
int iswdigit(wint_t);
int iswgraph(wint_t);
int iswlower(wint_t);
int iswprint(wint_t);
int iswpunct(wint_t);
int iswspace(wint_t);
int iswupper(wint_t);
int iswxdigit(wint_t);
int iswctype(wint_t, wctype_t);
wint_t towlower(wint_t);
wint_t towupper(wint_t);
wctype_t wctype(const char*);

#ifndef __cplusplus
#undef iswdigit
#define iswdigit(a) (0 ? iswdigit(a) : ((unsigned)(a) - '0') < 10)
#endif
#endif

#ifdef __cplusplus
}
#endif