//----------------------------------------------------------------------------//
//                           GNU GPL OS/K                                     //
//                                                                            //
//  Desc:       C Runtime Library                                             //
//                                                                            //
//                                                                            //
//  Copyright © 2018-2020 The OS/K Team                                       //
//                                                                            //
//  This file is part of OS/K.                                                //
//                                                                            //
//  OS/K is free software: you can redistribute it and/or modify              //
//  it under the terms of the GNU General Public License as published by      //
//  the Free Software Foundation, either version 3 of the License, or         //
//  any later version.                                                        //
//                                                                            //
//  OS/K is distributed in the hope that it will be useful,                   //
//  but WITHOUT ANY WARRANTY//without even the implied warranty of            //
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             //
//  GNU General Public License for more details.                              //
//                                                                            //
//  You should have received a copy of the GNU General Public License         //
//  along with OS/K.  If not, see <https://www.gnu.org/licenses/>.            //
//----------------------------------------------------------------------------//

#ifndef _LIBC_H
#define _LIBC_H

#ifdef __cplusplus
extern "C" {
#endif

//----------------------------------------------------------------------------//

typedef unsigned char       uchar;
typedef signed char         schar;
typedef unsigned short      ushort;
typedef unsigned int        uint;
typedef unsigned long       ulong;
typedef signed long long    llong;
typedef unsigned long long  ullong;
typedef long double         ldouble;

typedef unsigned long       size_t;
typedef signed long         ssize_t;
typedef signed int          wchar_t;
typedef unsigned long       off_t;
typedef unsigned long       time_t;
typedef signed long         ptrdiff_t;
typedef signed long         intptr_t;
typedef unsigned long       uintptr_t;
typedef signed long         intmax_t;
typedef unsigned long       uintmax_t;

typedef uint                error_t;
typedef __builtin_va_list   va_list;

//----------------------------------------------------------------------------//

#ifndef _KALEID_KERNEL

extern error_t __errno;
#define errno __errno
#define geterrno(x) ((x) = errno)
#define seterrno(x) (errno = (x))

#else

#define errno
#define geterrno(x) ((void)x)
#define seterrno(x) ((void)x)

#endif

#include <errno.h>

//----------------------------------------------------------------------------//

#if defined(_NO_DEBUG) || defined(NDEBUG)
#ifndef NDEBUG
#define NDEBUG 1
#endif
#ifndef _NO_DEBUG
#define _NO_DEBUG 1
#endif
#endif

//----------------------------------------------------------------------------//

#define alignof _Alignof
#define alignas _Alignas

#define static_assert _Static_assert
#define noreturn __attribute__((__noreturn__))

#define likely(x)   (__builtin_expect((x), 1))
#define unlikely(x) (__builtin_expect((x), 0))

#define va_start    __builtin_va_start
#define va_arg      __builtin_va_arg
#define va_copy     __builtin_va_copy
#define va_end      __builtin_va_end

//----------------------------------------------------------------------------//

void   *memset(void *, int, size_t);
void   *memsetw(void *, int, size_t);
void   *memsetd(void *, int, size_t);
void   *memsetq(void *, long, size_t);

void   *memrchr(const void *, int, size_t);

void   *memcpy(void *restrict, const void *restrict, size_t);
void   *memmove(void *, const void *, size_t);

void   *memzero(void *, size_t);
int     memcmp(const void *, const void *, size_t);

//----------------------------------------------------------------------------//

size_t  strlen(const char *);
size_t  strspn(const char *, const char *);
size_t  strcspn(const char *, const char *);

int     strcmp(const char *, const char *);
int     strncmp(const char *, const char *, size_t);

char   *strchr(const char *, int);
char   *strrchr(const char *, int);
char   *strchrnul(const char *, int);

char   *strstr(const char *, const char *);
char   *strpbrk(const char *, const char *);

char   *strtok(char *restrict, const char *restrict);
char   *strtok_r(char *restrict, const char *restrict, char **restrict);

char   *strcpy(char *restrict, const char *restrict);
char   *strncpy(char *restrict, const char *restrict, size_t);
char   *strnzcpy(char *restrict, const char *restrict, size_t);

char   *strcat(char *restrict, const char *restrict);
char   *strncat(char *restrict, const char *restrict, size_t);
char   *strnzcat(char *restrict, const char *restrict, size_t);

char   *strrev(char *restrict, const char *restrict);
char   *strrev2(char *);

size_t  sprintf(char *, const char *, ...);
size_t  snprintf(char *, size_t, const char *, ...);
size_t  vsprintf(char *, const char *, va_list);
size_t  vsnprintf(char *, size_t, const char *, va_list);

//----------------------------------------------------------------------------//

char   *itoa(int,  char *, int);
char   *ltoa(long, char *, int);
char   *utoa(unsigned int, char *, int);
char   *ultoa(unsigned long, char *, int);

int     atoi(const char *);
long    atol(const char *);
long    strtol(const char *restrict, char **restrict, int);

unsigned int atou(const char *);
unsigned long atoul(const char *);
unsigned long strtoul(const char *restrict, char **restrict, int);

//----------------------------------------------------------------------------//

void   *calloc(size_t, size_t) __attribute__((__malloc__));
void   *memalign(size_t n, size_t align) __attribute__((__malloc__));
void   *malloc(size_t) __attribute__((__malloc__));
void    free(void *);

//----------------------------------------------------------------------------//

int     rand(void);
void    srand(unsigned long);

//----------------------------------------------------------------------------//

const char    *strerror(error_t);
const char    *strsignal(int);

//----------------------------------------------------------------------------//

int     toupper(int);
int     tolower(int);

static inline int isascii(int __c)
{ return !(__c & ~0xff); }

//----------------------------------------------------------------------------//

extern int __ctype[];

#define _SH(x) (1 << (x))

enum
{
    _CT = _SH(0),   // control
    _PR = _SH(1),   // printing
    _GR = _SH(2),   // graphical
    _DX = _SH(3),   // hex digit
    _DG = _SH(4),   // decimal digit
    _SP = _SH(5),   // space
    _BK = _SH(6),   // blank
    _PT = _SH(7),   // punctuation
    _AL = _SH(8),   // alpha
    _UP = _SH(9),   // upper alpha
    _LW = _SH(10),  // lower alpha
};

#define _DECF(name, flag)  \
static inline int name(int __c)    \
{ return isascii(__c) ? !!(__ctype[__c] & flag) : 0; }

_DECF(iscntrl, _CT);
_DECF(isprint, _PR);
_DECF(isgraph, _GR);
_DECF(isdigit, _DG);
_DECF(isspace, _SP);
_DECF(isblank, _BK);
_DECF(ispunct, _PT);
_DECF(isalpha, _AL);
_DECF(isupper, _UP);
_DECF(islower, _LW);
_DECF(isxdigit, _DX);
_DECF(isalnum, (_AL|_DG));

#undef _SH
#undef _DECF

//----------------------------------------------------------------------------//

static inline int min(int __x, int __y) { return __x < __y ? __x : __y; }
static inline int max(int __x, int __y) { return __x > __y ? __x : __y; }
static inline int abs(int __x) { return __x < 0 ? -__x : __x; }

static inline long lmin(long __x, long __y) { return __x < __y ? __x : __y; }
static inline long lmax(long __x, long __y) { return __x > __y ? __x : __y; }
static inline long labs(long __x) { return __x < 0 ? -__x : __x; }

//----------------------------------------------------------------------------//

noreturn void __assert_handler(const char *, const char *, int, const char *);

#define assert_always(x) do { if unlikely (!(x)) \
     __assert_handler(#x, __FILE__, __LINE__, __func__); } while (0)

#ifndef NDEBUG
#define assert(x) assert_always(x)
#else
#define assert(x) ((void)0)
#endif

//----------------------------------------------------------------------------//


#define _SA_MSG "Incompatible type sizes"
static_assert(sizeof(char)   == 1, _SA_MSG);
static_assert(sizeof(short)  == 2, _SA_MSG);
static_assert(sizeof(int)    == 4, _SA_MSG);
static_assert(sizeof(long)   == 8, _SA_MSG);
static_assert(sizeof(void *) == 8, _SA_MSG);
#undef _SA_MSG

//----------------------------------------------------------------------------//

#define KB      (1UL << 10)
#define MB      (1UL << 20)
#define GB      (1UL << 30)
#define TB      (1UL << 40)

#define TRUE 1
#define FALSE 0
#define NULL 0L
#define BOOL int

#ifndef __cplusplus
#define bool int
#define true 1
#define false 0
#endif

#define RAND_MAX (1 << 30)
#define INITOK ((unsigned int)0xCAFEBABE)

#define _STR(x) #x
#define _XSTR(x) _STR(x)

#define _ALIGN_UP(x, s) (((x) + (s) - 1) & (~((s) - 1)))

//----------------------------------------------------------------------------//

#define BYTE            unsigned char
#define WORD            unsigned short
#define DWORD           unsigned int
#define QWORD           unsigned long

#define CHAR_BIT        8
#define BITS_IN(T)      (sizeof(T) * CHAR_BIT)

#define _ADDR_TO_MB(x)  ((x)>>20)
#define _ADDR_TO_KB(x)  (((x)>>10)&(KB-1))
#define _ADDR_TO_B(x)   ((x)&(KB-1))

#define SCHAR_MAX    0x7F
#define SHRT_MAX     0x7FFF
#define INT_MAX      0x7FFFFFFF
#define LONG_MAX     0x7FFFFFFFFFFFFFFFL
#define UCHAR_MAX    0xFFU
#define USHRT_MAX    0xFFFFU
#define UINT_MAX     0xFFFFFFFFU
#define ULONG_MAX    0xFFFFFFFFFFFFFFFFUL

#define SCHAR_MIN    (-SCHAR_MAX - 1)
#define SHRT_MIN     (-SHRT_MAX  - 1)
#define INT_MIN      (-INT_MAX   - 1)
#define LONG_MIN     (-LONG_MAX  - 1L)

#ifdef __CHAR_UNSIGNED__
#   define CHAR_MIN	((char)0)
#   define CHAR_MAX	((char)UCHAR_MAX)
#else
#   define CHAR_MIN	((char)SCHAR_MIN)
#   define CHAR_MAX	((char)SCHAR_MAX)
#endif

#define SSIZE_T_MIN      LONG_MIN
#define SSIZE_T_MAX      LONG_MAX
#define SIZE_T_MAX       ULONG_MAX

//----------------------------------------------------------------------------//

#define atomic_xadd(P, V)           __sync_fetch_and_add((P), (V))
#define atomic_cmpxchg(P, O, N)     __sync_val_compare_and_swap((P), (O), (N))
#define atomic_inc(P)               __sync_add_and_fetch((P), 1)
#define atomic_dec(P)               __sync_add_and_fetch((P), -1) 
#define atomic_add(P, V)            __sync_add_and_fetch((P), (V))
#define atomic_set_bit(P, V)        __sync_or_and_fetch((P), 1<<(V))
#define atomic_clear_bit(P, V)      __sync_and_and_fetch((P), ~(1<<(V)))

#define atomic_barrier() __sync_synchronize()

#define __relax_cpu() asm volatile("pause\n": : : "memory")

static inline void *atomic_xchg_64(volatile void *ptr, void *x)
{
	asm volatile ("xchgq %0,%1"
				:"=r" ((ulong) x)
				:"m" (*(volatile long *)ptr), "0" ((ulong) x)
				:"memory");

	return x;
}

static inline unsigned atomic_xchg_32(volatile void *ptr, uint x)
{
	asm volatile ("xchgl %0,%1"
				:"=r" ((uint) x)
				:"m" (*(volatile uint *)ptr), "0" (x)
				:"memory");

	return x;
}

static inline unsigned short atomic_xchg_16(volatile void *ptr, ushort x)
{
	asm volatile ("xchgw %0,%1"
				:"=r" ((unsigned short) x)
				:"m" (*(volatile ushort *)ptr), "0" (x)
				:"memory");

	return x;
}

static inline char atomic_bitsetandtest(volatile void *ptr, int x)
{
	char out;
	asm volatile ("lock; bts %2,%1\n"
						"sbb %0,%0\n"
				:"=r" (out), "=m" (*(volatile long *)ptr)
				:"Ir" (x)
				:"memory");

	return out;
}

//----------------------------------------------------------------------------//

#ifdef __cplusplus
}
#endif

#endif