This commit is contained in:
flysand7 2023-07-23 01:30:04 +11:00
parent da0f34325c
commit 31dbc0abd1
93 changed files with 858 additions and 9240 deletions

2
.gitignore vendored
View File

@ -1,5 +1,7 @@
bin
a.out
*.a
*.so
*.exe
*.lib
*.obj

View File

@ -1,6 +1,6 @@
# Generate the resources for UTF8
windres -o utf8.obj utf8.rc
windres -o utf8/utf8.obj utf8/utf8.rc
# Compile chkstk
nasm src\os_win\chkstk.asm -o chkstk.o -fwin64

18
build.sh Executable file
View File

@ -0,0 +1,18 @@
#!/bin/bash
[ ! -d "lib" ] && mkdir "lib"
[ ! -d "bin" ] && mkdir "bin"
nasm -f elf64 "src/linux/crt_entry.asm" -o "bin/crt_entry.o"
clang -fPIC -nostdlib -I "include" -g "src/linux/crt_ctors.c" -c -o "bin/crt_ctors.o"
clang -fPIC -nostdlib -I "include" -g "src/ciabatta.c" -c -o "bin/ciabatta.o"
rm "$LIB_FILE" 2> /dev/null
if [ "$1" != "-shared" ]; then
llvm-ar -q "lib/ciabatta.a" "bin/crt_ctors.o" "bin/crt_entry.o" "bin/ciabatta.o"
else
clang -fPIC -nostdlib -shared -o "lib/ciabatta.so" "bin/ciabatta.o"
cp "bin/crt_ctors.o" "lib/ctors.o"
cp "bin/crt_entry.o" "lib/entry.o"
fi

View File

@ -1,78 +0,0 @@
# assert.h - debug assertions
Macro definitions:
- [`assert(expr)`](#assert)
- [`static_assert`](#static-assert)
## [assert](#assert)
Assert a given condition is true, otherwise abort execution of a program.
The macro checks whether `expr` is true, and if not, prints the
diagnostic information and then aborts execution in a way equivalent to calling
abort() function (See SIGABRT).
If `_DEBUG` macro is defined, assert does not print a diagnostic message, and
instead simply causes a debug break.
If NDEBUG macro is defined assert expands to an empty statement. If both NDEBUG
and `_DEBUG` are defined, then `_DEBUG` macro is ignored.
```c
#if defined(NDEBUG)
#define assert(expr) ((void)0)
#elif defined(`_DEBUG`)
#define assert(expr) /* debug break */
#else
#define assert(expr) /* print diagnostic, then abort */
#endif
```
<details>
<summary>Example</summary>
```c
// Uncomment to disable assert
//#define NDEBUG
#include <assert.h>
int factorial(int n) {
assert(n >= 0);
if(n == 0) return 1;
return n*factorial(n-1);
}
int main() {
printf("Factorial of %d is %d\n", 10, factorial(10));
printf("Factorial of %d is %d\n", -1, factorial(-1));
return 0;
}
```
The first function would print 3628800, the second would trigger an assert.
Output:
```
Factorial of 10 is 3628800
Assertion failed: n >= 0
Function: factorial
File: test\test_assert.c
Line: 4
Trace:
4: factorial
3: main
2: mainCRTStartup
1: BaseThreadInitThunk
0: RtlUserThreadStart
```
</details>
## [static_assert](#static-assert)
Keyword macro that expands to C11 keyword `_Static_assert`.
```c
#define static_assert _Static_assert
```

View File

@ -1,4 +0,0 @@
# complex.h - complex number support
Not supported/implemented

View File

@ -1,42 +0,0 @@
# Ciabatta
Ciabatta is a C standard library implementation. The goal is to provide a
cross-platform implementation that provides it's own documentation, clarifying
implementation-defined details, as well as provides additional functionality,
like sockets, or unicode processing, the kind of functionality that is used
in different kinds of programs.
## Headers
The implementation doesn't provide all headers. The headers that aren't
provided are supposed to be provided by compiler. The list of such headers:
- stdarg.h
- setjmp.h
The headers that are provided have documentation included:
- [assert.h](assert.md)
- [complex.h](complex.md)
- [ctype.h](ctype.md)
- [errno.h](errno.md)
- [fenv.h](fenv.md)
- [inttypes.h](inttypes.md)
- [locale.h](locale.md)
- [math.h](math.md)
- [signal.h](signal.md)
- [stdio.h](stdio.md)
- [stdlib.h](stdlib.md)
- [string.h](string.md)
- [tgmath.h](tgmath.md)
- [threads.h](threads.md)
- [time.h](time.md)
- [uchar.h](uchar.md)
- [wchar.h](wchar.md)
- [wctype.h](wctype.md)
## Locales
Not supported. The `char *` strings are assumed to be encoded using ASCII/UTF-8
encoding.

View File

@ -1,13 +0,0 @@
#pragma once
enum memory_order {
memory_order_relaxed,
memory_order_consume,
memory_order_acquire,
memory_order_release,
memory_order_acq_rel,
memory_order_seq_cst
};
typedef int atomic_int;

View File

@ -1,35 +0,0 @@
#pragma once
#if defined(_MSC_VER) && !defined(__clang__)
#define _Noreturn
#endif
void _assert(
char const *cond,
char const *func,
char const *file,
int line
);
#if defined(NDEBUG)
#define assert(ignore) ((void)0)
#elif defined(_DEBUG)
#if defined(__GNUC__) || defined(__CUIKC__)
#define assert(c) if (!(c)) __builtin_trap()
#elif defined(_MSC_VER)
#define assert(c) if (!(c)) __debugbreak()
#else
// In debug mode there shouldn't be any optimizations so this should
// work as a simple way to cause a trap.
#define assert(c) do { if (!(c)) *(volatile int *)0 = 0; } while(0)
#endif
#else
#define _static_assert _Static_assert
#define assert(condition) \
do { \
if(!(condition)) { \
_assert(#condition, __func__, __FILE__, __LINE__); \
} \
} while(0)
#endif

69
include/cia_definitions.h Normal file
View File

@ -0,0 +1,69 @@
#pragma once
// Pre-C23 keyword macros
#define static_assert _Static_assert
// Platform macros
#define CIA_LINUX 1
#define CIA_WINDOWS 2
#define CIA_ANDROID 3
// Platform detection
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)
#define CIA_OS CIA_WINDOWS
#if !defined(_WIN64)
#error "32-bit windows is not supported"
#endif
#elif __APPLE__
#error "Apple OS's not supported and will never be unless you want to write the support for it"
#elif __ANDROID__
#define CIA_OS CIA_ANDROID
#elif __linux__
#define CIA_OS CIA_LINUX
#else
#error "Unable to detect the OS"
#endif
// Convenience platform checking macros
#define os_is_linux() (CIA_OS == CIA_LINUX)
#define os_is_windows() (CIA_OS == CIA_WINDOWS)
#define os_is_android() (CIA_OS == CIA_ANDROID)
// Assert commonly-accepted platform-invariant sizes
static_assert(sizeof(char) == 1, "Char isn't 1 bytes long");
static_assert(sizeof(short) == 2, "Short isn't 2 bytes long");
static_assert(sizeof(int) == 4, "Int isn't 4 bytes long");
static_assert(sizeof(long long int) == 8, "Long long isn't 8 bytes long");
#if os_is_linux()
static_assert(sizeof(long) == 8, "Long on linux isn't 8 bytes");
#elif os_is_windows()
static_assert(sizeof(long) == 4, "Long on windows isn't 4 bytes");
#endif
// stdint.h type definitions
typedef signed char int8_t;
typedef unsigned char uint8_t;
typedef signed short int16_t;
typedef unsigned short uint16_t;
typedef signed int int32_t;
typedef unsigned int uint32_t;
#if os_is_linux()
typedef signed long int64_t;
typedef unsigned long uint64_t;
#elif os_is_windows()
typedef signed long long int64_t;
typedef unsigned long long uint64_t;
#else
#error "Platform not implemented"
#endif
// Short type definitions
typedef int8_t i8;
typedef uint8_t u8;
typedef int16_t i16;
typedef uint16_t u16;
typedef int32_t i32;
typedef uint32_t u32;
typedef int64_t i64;
typedef uint64_t u64;

View File

@ -1,4 +0,0 @@
#pragma once
#error "Complex Numbers aren't implemented"

View File

@ -1,17 +0,0 @@
#pragma once
int isalnum(int c);
int isalpha(int c);
int isblank(int c);
int iscntrl(int c);
int isdigit(int c);
int isgraph(int c);
int islower(int c);
int isprint(int c);
int ispunct(int c);
int isspace(int c);
int isupper(int c);
int isxdigit(int c);
int tolower(int c);
int toupper(int c);

View File

@ -1,13 +0,0 @@
#pragma once
#define EDOM 1
#define EILSEQ 2
#define ERANGE 3
// TODO: figure out why _Thread_local doesn't work
extern _Thread_local int errno;
#if __STDC_WANT_LIB_EXT1__ == 1
typedef int errno_t;
#endif

View File

@ -1,62 +0,0 @@
#pragma once
typedef unsigned fexcept_t;
typedef unsigned fenv_t;
// These constants correspond to bits in MXCSR register
#define FE_INVALID (1 << 0)
#define FE_DIVBYZERO (1 << 2)
#define FE_OVERFLOW (1 << 3)
#define FE_UNDERFLOW (1 << 4)
#define FE_INEXACT (1 << 5)
#define FE_DENORM (1 << 1)
#define FE_DAZ (1 << 6)
#define FE_ALL_EXCEPT \
( FE_INVALID \
| FE_DIVBYZERO \
| FE_OVERFLOW \
| FE_UNDERFLOW \
| FE_INEXACT \
| FE_DENORM \
| FE_DAZ )
// These constants correspond to the rounding field in MXCSR register
#define FE_TONEAREST 0x00
#define FE_DOWNWARD 0x01
#define FE_UPWARD 0x02
#define FE_TOWARDZERO 0x03
extern fenv_t _fe_dfl_env;
#define FE_DFL_ENV (&_fe_dfl_env)
// Exceptions
int feclearexcept(int excepts);
int fegetexceptflag(fexcept_t *flagp, int excepts);
int feraiseexcept(int excepts);
int fesetexceptflag(const fexcept_t *flagp, int excepts);
int fetestexcept(int excepts);
// Rounding behaviour
int fegetround(void);
int fesetround(int round);
// Environment
int fegetenv(fenv_t *env);
int fesetenv(fenv_t *env);
int feholdexcept(fenv_t *envp);
int feupdateenv(fenv_t const *envp);
// Non-standard functions
int _feenabletraps(int excepts);
int _fedisabletraps(int excepts);
#if defined(_CIABATTA_EXT)
#define feenabletraps _feenabletraps
#define fedisabletraps _fedisabletraps
#endif

View File

@ -1,43 +0,0 @@
#pragma once
#define DECIMAL_DIG 10
#define FLT_ROUNDS 1
#define FLT_EVAL_METHOD 0
#define FLT_RADIX 2
#define FLT_DECIMAL_DIG 6
#define FLT_MIN 0x1.000000p-126
#define FLT_MAX 0x1.7ffffep+127
#define FLT_TRUE_MIN 0x1.000000p-149
#define FLT_EPSILON 0x1.000002p+0
#define FLT_MANT_DIG 23
#define FLT_MIN_EXP -125
#define FLT_MAX_EXP +128
#define FLT_MIN_10_EXP -37
#define FLT_MAX_10_EXP +38
#define FLT_HAS_SUBNORM 1
#define DBL_DECIMAL_DIG 10
#define DBL_MIN 0x1.0000000000000p-1022
#define DBL_MAX 0x1.fffffffffffffp+1023
#define DBL_TRUE_MIN 0x1.0000000000000p-1074
#define DBL_EPSILON 0x1.0000000000001p+0
#define DBL_MANT_DIG 11
#define DBL_MIN_EXP -1022
#define DBL_MAX_EXP +1024
#define DBL_MIN_10_EXP -307
#define DBL_MAX_10_EXP +308
#define DBL_HAS_SUBNORM 1
#define LDBL_DECIMAL_DIG DBL_DECIMAL_DIG
#define LDBL_MIN DBL_MIN
#define LDBL_MAX DBL_MAX
#define LDBL_TRUE_MIN DBL_TRUE_MIN
#define LDBL_EPSILON DBL_EPSILON
#define LDBL_MANT_DIG DBL_MANT_DIG
#define LDBL_MIN_EXP DBL_MIN_EXP
#define LDBL_MIN_10_EXP DBL_MIN_10_EXP
#define LDBL_MAX_EXP DBL_MAX_EXP
#define LDBL_MAX_10_EXP DBL_MAX_10_EXP
#define LDBL_HAS_SUBNORM DBL_HAS_SUBNORM

View File

@ -1,275 +0,0 @@
#pragma once
#include <stdint.h>
#define PRIi8 "hhi"
#define PRIu8 "hhu"
#define PRIo8 "hho"
#define PRId8 "hhd"
#define PRIx8 "hhx"
#define PRIX8 "hhX"
#define PRIi16 "hi"
#define PRIu16 "hu"
#define PRIo16 "ho"
#define PRId16 "hd"
#define PRIx16 "hx"
#define PRIX16 "hX"
#define PRIi32 "i"
#define PRIu32 "u"
#define PRIo32 "o"
#define PRId32 "d"
#define PRIx32 "x"
#define PRIX32 "X"
#if defined(_WIN64)
#define PRIi64 "lli"
#define PRIu64 "llu"
#define PRIo64 "llo"
#define PRId64 "lld"
#define PRIx64 "llx"
#define PRIX64 "llX"
#else
#define PRIi64 "li"
#define PRIu64 "lu"
#define PRIo64 "lo"
#define PRId64 "ld"
#define PRIx64 "lx"
#define PRIX64 "lX"
#endif
#define PRIdLEAST8 "hhi"
#define PRIuLEAST8 "hhu"
#define PRIoLEAST8 "hho"
#define PRIiLEAST8 "hhd"
#define PRIxLEAST8 "hhx"
#define PRIXLEAST8 "hhX"
#define PRIiLEAST16 "hi"
#define PRIuLEAST16 "hu"
#define PRIoLEAST16 "ho"
#define PRIdLEAST16 "hd"
#define PRIxLEAST16 "hx"
#define PRIXLEAST16 "hX"
#define PRIiLEAST32 "i"
#define PRIuLEAST32 "u"
#define PRIoLEAST32 "o"
#define PRIdLEAST32 "d"
#define PRIxLEAST32 "x"
#define PRIXLEAST32 "X"
#if defined(_WIN32)
#define PRIiLEAST64 "lli"
#define PRIuLEAST64 "llu"
#define PRIoLEAST64 "llo"
#define PRIdLEAST64 "lld"
#define PRIxLEAST64 "llx"
#define PRIXLEAST64 "llX"
#else
#define PRIiLEAST64 "li"
#define PRIuLEAST64 "lu"
#define PRIoLEAST64 "lo"
#define PRIdLEAST64 "ld"
#define PRIxLEAST64 "lx"
#define PRIXLEAST64 "lX"
#endif
#define PRIiFAST8 "i"
#define PRIuFAST8 "u"
#define PRIoFAST8 "o"
#define PRIdFAST8 "d"
#define PRIxFAST8 "x"
#define PRIXFAST8 "X"
#define PRIiFAST16 "i"
#define PRIuFAST16 "u"
#define PRIoFAST16 "o"
#define PRIdFAST16 "d"
#define PRIxFAST16 "x"
#define PRIXFAST16 "X"
#define PRIiFAST32 "i"
#define PRIuFAST32 "u"
#define PRIoFAST32 "o"
#define PRIdFAST32 "d"
#define PRIxFAST32 "x"
#define PRIXFAST32 "X"
#if defined(_WIN32)
#define PRIiFAST64 "lli"
#define PRIuFAST64 "llu"
#define PRIoFAST64 "llo"
#define PRIdFAST64 "lld"
#define PRIxFAST64 "llx"
#define PRIXFAST64 "llX"
#define PRIiPTR "lli"
#define PRIuPTR "llu"
#define PRIoPTR "llo"
#define PRIdPTR "lld"
#define PRIxPTR "llx"
#define PRIXPTR "llX"
#define PRIiMAX "lli"
#define PRIuMAX "llu"
#define PRIoMAX "llo"
#define PRIdMAX "lld"
#define PRIxMAX "llx"
#define PRIXMAX "llX"
#else
#define PRIiFAST64 "li"
#define PRIuFAST64 "lu"
#define PRIoFAST64 "lo"
#define PRIdFAST64 "ld"
#define PRIxFAST64 "lx"
#define PRIXFAST64 "lX"
#define PRIiPTR "li"
#define PRIuPTR "lu"
#define PRIoPTR "lo"
#define PRIdPTR "ld"
#define PRIxPTR "lx"
#define PRIXPTR "lX"
#define PRIiMAX "li"
#define PRIuMAX "lu"
#define PRIoMAX "lo"
#define PRIdMAX "ld"
#define PRIxMAX "lx"
#define PRIXMAX "lX"
#endif
#define SCNi8 "hhi"
#define SCNu8 "hhu"
#define SCNo8 "hho"
#define SCNd8 "hhd"
#define SCNx8 "hhx"
#define SCNiLEAST8 "hhi"
#define SCNuLEAST8 "hhu"
#define SCNoLEAST8 "hho"
#define SCNdLEAST8 "hhd"
#define SCNxLEAST8 "hhx"
#define SCNdFAST8 "hhd"
#define SCNiFAST8 "hhi"
#define SCNoFAST8 "hho"
#define SCNuFAST8 "hhu"
#define SCNxFAST8 "hhx"
#define SCNi16 "hi"
#define SCNu16 "hu"
#define SCNo16 "ho"
#define SCNd16 "hd"
#define SCNx16 "hx"
#define SCNiLEAST16 "hi"
#define SCNuLEAST16 "hu"
#define SCNoLEAST16 "ho"
#define SCNdLEAST16 "hd"
#define SCNxLEAST16 "hx"
#define SCNiFAST16 "i"
#define SCNuFAST16 "u"
#define SCNoFAST16 "o"
#define SCNdFAST16 "d"
#define SCNxFAST16 "x"
#define SCNi32 "i"
#define SCNu32 "u"
#define SCNo32 "o"
#define SCNd32 "d"
#define SCNx32 "x"
#define SCNiFAST32 "i"
#define SCNuFAST32 "u"
#define SCNoFAST32 "o"
#define SCNdFAST32 "d"
#define SCNxFAST32 "x"
#define SCNiLEAST32 "i"
#define SCNuLEAST32 "u"
#define SCNoLEAST32 "o"
#define SCNdLEAST32 "d"
#define SCNxLEAST32 "x"
#if defined(_WIN32)
#define SCNi64 "lli"
#define SCNu64 "llu"
#define SCNo64 "llo"
#define SCNd64 "lld"
#define SCNx64 "llx"
#define SCNiLEAST64 "lli"
#define SCNuLEAST64 "llu"
#define SCNoLEAST64 "llo"
#define SCNdLEAST64 "lld"
#define SCNxLEAST64 "llx"
#define SCNiFAST64 "lli"
#define SCNuFAST64 "llu"
#define SCNoFAST64 "llo"
#define SCNdFAST64 "lld"
#define SCNxFAST64 "llx"
#define SCNiMAX "lli"
#define SCNuMAX "llu"
#define SCNoMAX "llo"
#define SCNdMAX "lld"
#define SCNxMAX "llx"
#define SCNiPTR "lli"
#define SCNuPTR "llu"
#define SCNoPTR "llo"
#define SCNdPTR "lld"
#define SCNxPTR "llx"
#else
#define SCNi64 "li"
#define SCNu64 "lu"
#define SCNo64 "lo"
#define SCNd64 "ld"
#define SCNx64 "lx"
#define SCNiLEAST64 "li"
#define SCNuLEAST64 "lu"
#define SCNoLEAST64 "lo"
#define SCNdLEAST64 "ld"
#define SCNxLEAST64 "lx"
#define SCNiFAST64 "li"
#define SCNuFAST64 "lu"
#define SCNoFAST64 "lo"
#define SCNdFAST64 "ld"
#define SCNxFAST64 "lx"
#define SCNiMAX "li"
#define SCNuMAX "lu"
#define SCNoMAX "lo"
#define SCNdMAX "ld"
#define SCNxMAX "lx"
#define SCNiPTR "li"
#define SCNuPTR "lu"
#define SCNoPTR "lo"
#define SCNdPTR "ld"
#define SCNxPTR "lx"
#endif
#if defined(_WIN32)
typedef unsigned short wchar_t;
#else
typedef int wchar_t;
#endif
typedef struct imaxdiv_t imaxdiv_t;
struct imaxdiv_t {
intmax_t quot;
intmax_t rem;
};
intmax_t imaxabs(intmax_t j);
imaxdiv_t imaxdiv(intmax_t numer, intmax_t denom);
intmax_t strtoimax(const char *restrict s, char **restrict end, int base);
uintmax_t strtoumax(const char *restrict s, char ** restrict end, int base);
intmax_t wcstoimax(const wchar_t *restrict s, wchar_t **restrict end, int base);
uintmax_t wcstoumax(const wchar_t *restrict s, wchar_t **restrict end, int base);

View File

@ -1,14 +0,0 @@
#pragma once
#define and &&
#define and_eq &=
#define bitand &
#define bitor |
#define compl ~
#define not !
#define not_eq !=
#define or ||
#define or_eq |=
#define xor ^
#define xor_eq ^=

View File

@ -1,87 +0,0 @@
#pragma once
#define MB_LEN_MAX 5
#define CHAR_BIT 8
#define BOOL_WIDTH 8
#define UCHAR_WIDTH 8
#define SCHAR_WIDTH 8
#define UCHAR_MAX 0xff
#define SCHAR_MIN -0x80
#define SCHAR_MAX +0x7f
#if defined(__CHAR_UNSIGNED__) || defined(_CHAR_UNSIGNED)
#define CHAR_MIN UCHAR_MIN
#define CHAR_MAX UCHAR_MAX
#else
#define CHAR_MIN SCHAR_MIN
#define CHAR_MAX SCHAR_MAX
#endif
#define USHRT_WIDTH 16
#define SHRT_WIDTH 16
#define USHRT_MAX 0xffff
#define SHRT_MIN -0x8000
#define SHRT_MAX +0x7fff
#define UINT_WIDTH 32
#define INT_WIDTH 32
#define UINT_MAX 0xffffffffu
#define INT_MIN -0x80000000
#define INT_MAX +0x7fffffff
#if defined(_WIN64)
#define ULONG_WIDTH 32
#define LONG_WIDTH 32
#define ULONG_MAX +0xffffffff
#define LONG_MIN -0x80000000
#define LONG_MAX +0x7fffffff
#else
#define ULONG_WIDTH 64
#define LONG_WIDTH 64
#define ULONG_MAX 0xffffffffffffffffull
#define LONG_MIN -0x8000000000000000ll
#define LONG_MAX +0x7fffffffffffffffll
#endif
#define ULLONG_WIDTH 64
#define LLONG_WIDTH 64
#define ULLONG_MAX 0xffffffffffffffffull
#define LLONG_MIN -0x8000000000000000ll
#define LLONG_MAX +0x7fffffffffffffffll
#define PTRDIFF_WIDTH LLONG_WIDTH
#define PTRDIFF_MIN LLONG_MIN
#define PTRDIFF_MAX LLONG_MAX
#define SIZE_WIDTH ULLONG_WIDTH
#define SIZE_MAX ULLONG_MAX
#define SIG_ATOMIC_WIDTH LLONG_WIDTH
#define SIG_ATOMIC_MIN LLONG_MIN
#define SIG_ATOMIC_MAX LLONG_MAX
#define WINT_WIDTH INT_WIDTH
#define WINT_MIN INT_MIN
#define WINT_MAX INT_MAX
#define CHAR_WIDTH 8
#define WCHAR_WIDTH USHORT_WIDTH
#if !defined(WCHAR_MIN)
#if defined(_WIN32)
#define WCHAR_MIN 0
#else
#define WCHAR_MIN INT_MIN
#endif
#endif
#if !defined(WCHAR_MAX)
#if defined(_WIN32)
#define WCHAR_MAX USHORT_MAX
#else
#define WCHAR_MAX INT_MAX
#endif
#endif

View File

@ -1,45 +0,0 @@
#pragma once
#define _COL_IGNORE_SPACE 0x1
#define _COL_IGNORE_SYMBOL 0x2
// Locale categories
#define LC_ALL 0
#define LC_COLLATE 1
#define LC_CTYPE 2
#define LC_MONETARY 3
#define LC_NUMERIC 4
#define LC_TIME 5
struct lconv {
// LC_NUMERIC
char *decimal_point; // "."
char *thousands_sep; // ""
char *grouping; // ""
// LC_MONETARY
char *mon_decimal_point; // ""
char *mon_thousands_sep; // ""
char *mon_grouping; // ""
char *positive_sign; // ""
char *negative_sign; // ""
char *currency_symbol; // ""
char frac_digits; // CHAR_MAX
char p_cs_precedes; // CHAR_MAX
char n_cs_precedes; // CHAR_MAX
char p_sep_by_space; // CHAR_MAX
char n_sep_by_space; // CHAR_MAX
char p_sign_posn; // CHAR_MAX
char n_sign_posn; // CHAR_MAX
char *int_curr_symbol; // ""
char int_frac_digits; // CHAR_MAX
char int_p_cs_precedes; // CHAR_MAX
char int_n_cs_precedes; // CHAR_MAX
char int_p_sep_by_space; // CHAR_MAX
char int_n_sep_by_space; // CHAR_MAX
char int_p_sign_posn; // CHAR_MAX
char int_n_sign_posn; // CHAR_MAX
};
char *setlocale(int category, const char *locale);
struct lconv *localeconv(void);

View File

@ -1,301 +0,0 @@
#pragma once
typedef float float_t;
typedef double double_t;
#ifndef _HUGE_ENUF
#define _HUGE_ENUF 1e+300 // _HUGE_ENUF*_HUGE_ENUF must overflow
#endif
#define INFINITY ((float)(_HUGE_ENUF * _HUGE_ENUF))
#define HUGE_VAL ((double)INFINITY)
#define HUGE_VALF ((float)INFINITY)
#define NAN (-(float)(INFINITY * 0.0F))
#define FP_ILOGBNAN (-1-0x7fffffff)
#define FP_ILOGB0 FP_ILOGBNAN
#define MATH_ERRNO 1
#define MATH_ERREXCEPT 2
#define math_errhandling (MATH_ERRNO | MATH_ERREXCEPT)
// Classification
#define FP_ZERO 0
#define FP_SUBNORMAL 1
#define FP_NORMAL 2
#define FP_INFINITE 4
#define FP_NAN 5
int _fpclassify(double);
int _fpclassifyf(float);
int _fpclassifyl(long double);
#define fpclassify(x) (sizeof(x)==4?_fpclassifyf(x) \
:sizeof(x)==8?_fpclassify(x) \
: _fpclassifyl(x) )
#define isfinite(x) (fpclassify(x) != FP_INFINITE && fpclassify(x) != FP_NAN)
#define isinf(x) (fpclassify(x) == FP_INFINITE)
#define isnan(x) (fpclassify(x) == FP_NAN)
#define isnormal(x) (fpclassify(x) == FP_NORMAL)
// signbit shit
int _signbit(double);
int _signbitf(float);
int _signbitl(long double);
#define signbit(x) (sizeof(x) == sizeof(float) ? _signbitf(x) \
:sizeof(x) == sizeof(double) ? _signbit(x) \
: _signbitl(x) )
// Ordering
#define isunordered(x,y) (isnan((x)) ? ((void)(y),1) : isnan((y)))
#define isgreater(x,y) (!isunordered(x,y) && ((x) > (y)))
#define isgreaterequal(x,y) (!isunordered(x,y) && ((x) >= (y)))
#define isless(x,y) (!isunordered(x,y) && ((x) < (y)))
#define islessequal(x,y) (!isunordered(x,y) && ((x) <= (y)))
#define islessgreater(x,y) (!isunordered(x,y) && ((x) != (y)))
#if defined(_USE_MATH_DEFINES)
#define M_E 2.7182818284590452354
#define M_LOG2E 1.4426950408889634074
#define M_LOG10E 0.43429448190325182765
#define M_LN2 0.69314718055994530942
#define M_LN10 2.30258509299404568402
#define M_PI 3.14159265358979323846
#define M_PI_2 1.57079632679489661923
#define M_PI_4 0.78539816339744830962
#define M_1_PI 0.31830988618379067154
#define M_2_PI 0.63661977236758134308
#define M_2_SQRTPI 1.12837916709551257390
#define M_SQRT2 1.41421356237309504880
#define M_SQRT1_2 0.70710678118654752440
#endif
// Floating-point function prototypes
double acos (double);
float acosf (float);
long double acosl (long double);
double acosh (double);
float acoshf (float);
long double acoshl (long double);
double asin (double);
float asinf (float);
long double asinl (long double);
double asinh (double);
float asinhf (float);
long double asinhl (long double);
double atan (double);
float atanf (float);
long double atanl (long double);
double atan2 (double, double);
float atan2f (float, float);
long double atan2l (long double, long double);
double atanh (double);
float atanhf (float);
long double atanhl (long double);
double cbrt (double);
float cbrtf (float);
long double cbrtl (long double);
double ceil (double);
float ceilf (float);
long double ceill (long double);
double copysign (double, double);
float copysignf (float, float);
long double copysignl (long double, long double);
double cos (double);
float cosf (float);
long double cosl (long double);
double cosh (double);
float coshf (float);
long double coshl (long double);
double erf (double);
float erff (float);
long double erfl (long double);
double erfc (double);
float erfcf (float);
long double erfcl (long double);
double exp (double);
float expf (float);
long double expl (long double);
double exp2 (double);
float exp2f (float);
long double exp2l (long double);
double expm1 (double);
float expm1f (float);
long double expm1l (long double);
double fabs (double);
float fabsf (float);
long double fabsl (long double);
double fdim (double, double);
float fdimf (float, float);
long double fdiml (long double, long double);
double floor (double);
float floorf (float);
long double floorl (long double);
double fma (double, double, double);
float fmaf (float, float, float);
long double fmal (long double, long double, long double);
double fmax (double, double);
float fmaxf (float, float);
long double fmaxl (long double, long double);
double fmin (double, double);
float fminf (float, float);
long double fminl (long double, long double);
double fmod (double, double);
float fmodf (float, float);
long double fmodl (long double, long double);
double frexp (double, int *);
float frexpf (float, int *);
long double frexpl (long double, int *);
double hypot (double, double);
float hypotf (float, float);
long double hypotl (long double, long double);
int ilogb (double);
int ilogbf (float);
int ilogbl (long double);
double ldexp (double, int);
float ldexpf (float, int);
long double ldexpl (long double, int);
double lgamma (double);
float lgammaf (float);
long double lgammal (long double);
long long llrint (double);
long long llrintf (float);
long long llrintl (long double);
long long llround (double);
long long llroundf (float);
long long llroundl (long double);
double log (double);
float logf (float);
long double logl (long double);
double log10 (double);
float log10f (float);
long double log10l (long double);
double log1p (double);
float log1pf (float);
long double log1pl (long double);
double log2 (double);
float log2f (float);
long double log2l (long double);
double logb (double);
float logbf (float);
long double logbl (long double);
long lrint (double);
long lrintf (float);
long lrintl (long double);
long lround (double);
long lroundf (float);
long lroundl (long double);
double modf (double, double *);
float modff (float, float *);
long double modfl (long double, long double *);
double nan (const char *);
float nanf (const char *);
long double nanl (const char *);
double nearbyint (double);
float nearbyintf (float);
long double nearbyintl (long double);
double nextafter (double, double);
float nextafterf (float, float);
long double nextafterl (long double, long double);
double nexttoward (double, long double);
float nexttowardf(float, long double);
long double nexttowardl(long double, long double);
double pow (double, double);
float powf (float, float);
long double powl (long double, long double);
double remainder (double, double);
float remainderf (float, float);
long double remainderl (long double, long double);
double remquo (double, double, int *);
float remquof (float, float, int *);
long double remquol (long double, long double, int *);
double rint (double);
float rintf (float);
long double rintl (long double);
double round (double);
float roundf (float);
long double roundl (long double);
double scalbln (double, long);
float scalblnf (float, long);
long double scalblnl (long double, long);
double scalbn (double, int);
float scalbnf (float, int);
long double scalbnl (long double, int);
double sin (double);
float sinf (float);
long double sinl (long double);
double sinh (double);
float sinhf (float);
long double sinhl (long double);
double sqrt (double);
float sqrtf (float);
long double sqrtl (long double);
double tan (double);
float tanf (float);
long double tanl (long double);
double tanh (double);
float tanhf (float);
long double tanhl (long double);
double tgamma (double);
float tgammaf (float);
long double tgammal (long double);
double trunc (double);
float truncf (float);
long double truncl (long double);

View File

@ -1,38 +0,0 @@
// Note(bumbread): this file is included into threads.h when compiled under
// windows. Here we avoid including windows.h directly because it may be
// undesireable to include a bunch of non-standard names and types into user's
// files just to get a few of them.
#pragma once
#define ONCE_FLAG_INIT ((once_flag){0})
typedef struct thrd_t {
void *handle;
} thrd_t;
typedef struct tss_t {
unsigned tls_index;
} tss_t;
// We pretend that once_flag defined the same way as INIT_ONCE
// from winapi headers (aka _RTL_RUN_ONCE), which itself is defined
// as a union
typedef union once_flag {
void *ptr;
} once_flag;
// This mirrors CONDITION_VARIABLE type (aka _RTL_CONDITION_VARIABLE)
typedef struct cnd_t {
void *ptr;
} cnd_t;
typedef struct mtx_t {
int type;
// Done to handle recursive mutexes
unsigned long recursion;
unsigned long owner;
_Atomic(int) counter;
void* semaphore;
} mtx_t;

View File

@ -1,26 +0,0 @@
#pragma once
typedef int sig_atomic_t;
// TODO: idk about SIG_ERR, for now this
#define SIG_ERR ((void(*)(int))0)
#define SIG_DFL _signal_default_handler
#define SIG_IGN _signal_ignore_handler
// Note(bumbread): from the impl standpoint the numbers are arbitrary
#define _SIG_MIN 0
#define SIGINT 1
#define SIGILL 2
#define SIGFPE 3
#define SIGSEGV 4
#define SIGTERM 5
#define SIGABRT 6
// These guys are impl defined
#define SIGBREAK 7
#define SIGALIGN 8
#define SIGSTEP 9
#define _SIG_MAX 9
void (*signal(int sig, void (*func)(int)))(int);
int raise(int sig);

View File

@ -1,31 +0,0 @@
#pragma once
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <fenv.h>
#include <float.h>
#include <inttypes.h>
#include <iso646.h>
#include <limits.h>
#include <locale.h>
#include <math.h>
#include <setjmp.h>
#include <signal.h>
#include <stdalign.h>
#include <stdarg.h>
#include <stdatomic.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdnoreturn.h>
#include <string.h>
// #include <tgmath.h>
#include <threads.h>
#include <time.h>
#include <uchar.h>
#include <wchar.h>
#include <wctype.h>

View File

@ -1,8 +0,0 @@
#pragma once
#define __alignas_is_defined 1
#define __alignof_is_defined 1
#define alignas _Alignas
#define alignof _Alignof

View File

@ -1,8 +0,0 @@
#pragma once
#define __bool_true_false_are_defined 1
#define bool _Bool
#define true 1
#define false 0

View File

@ -1,24 +0,0 @@
#pragma once
#if !defined(NULL)
#define NULL ((void *)0)
#endif
#define offsetof(st, m) ((size_t)((char *)&((st *)0)->m - (char *)0))
#if defined(_WIN32)
typedef long long ptrdiff_t;
typedef unsigned long long size_t;
typedef unsigned long long max_align_t;
typedef unsigned short wchar_t;
#else
typedef long ptrdiff_t;
typedef unsigned long size_t;
typedef unsigned long max_align_t;
typedef int wchar_t;
#endif
#if __STDC_WANT_LIB_EXT1__ == 1
typedef size_t rsize_t;
#endif

View File

@ -1,153 +0,0 @@
#pragma once
typedef signed char int8_t;
typedef short int16_t;
typedef int int32_t;
typedef long long int64_t;
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
#if defined(_WIN64)
typedef unsigned long long uint64_t;
#else
typedef unsigned long uint64_t;
#endif
typedef int8_t int_least8_t;
typedef int16_t int_least16_t;
typedef int32_t int_least32_t;
typedef int64_t int_least64_t;
typedef uint8_t uint_least8_t;
typedef uint16_t uint_least16_t;
typedef uint32_t uint_least32_t;
typedef uint64_t uint_least64_t;
typedef int32_t int_fast8_t;
typedef int32_t int_fast16_t;
typedef int32_t int_fast32_t;
typedef int64_t int_fast64_t;
typedef uint32_t uint_fast8_t;
typedef uint32_t uint_fast16_t;
typedef uint32_t uint_fast32_t;
typedef uint64_t uint_fast64_t;
typedef int64_t intptr_t;
typedef uint64_t uintptr_t;
typedef int64_t intmax_t;
typedef uint64_t uintmax_t;
#define INT8_WIDTH 8
#define INT16_WIDTH 16
#define INT32_WIDTH 32
#define INT64_WIDTH 64
#define UINT8_WIDTH 8
#define UINT16_WIDTH 16
#define UINT32_WIDTH 32
#define UINT64_WIDTH 64
#define INT8_MIN -0x80
#define INT16_MIN -0x8000
#define INT32_MIN -0x80000000
#define INT64_MIN -0x8000000000000000ll
#define INT8_MAX +0x7f
#define INT16_MAX +0x7fff
#define INT32_MAX +0x7fffffff
#define INT64_MAX +0x7fffffffffffffff
#define UINT8_MAX +0xff
#define UINT16_MAX +0xffff
#define UINT32_MAX +0xffffffffu
#define UINT64_MAX +0xffffffffffffffffull
#define INT_LEAST8_WIDTH INT8_WIDTH
#define INT_LEAST16_WIDTH INT16_WIDTH
#define INT_LEAST32_WIDTH INT32_WIDTH
#define INT_LEAST64_WIDTH INT64_WIDTH
#define UINT_LEAST8_WIDTH INT8_WIDTH
#define UINT_LEAST16_WIDTH INT16_WIDTH
#define UINT_LEAST32_WIDTH INT32_WIDTH
#define UINT_LEAST64_WIDTH INT64_WIDTH
#define INT_LEAST8_MIN INT8_MIN
#define INT_LEAST16_MIN INT16_MIN
#define INT_LEAST32_MIN INT32_MIN
#define INT_LEAST64_MIN INT64_MIN
#define INT_LEAST8_MAX INT8_MAX
#define INT_LEAST16_MAX INT16_MAX
#define INT_LEAST32_MAX INT32_MAX
#define INT_LEAST64_MAX INT64_MAX
#define UINT_LEAST8_MAX UINT8_MAX
#define UINT_LEAST16_MAX UINT16_MAX
#define UINT_LEAST32_MAX UINT32_MAX
#define UINT_LEAST64_MAX UINT64_MAX
#define INT_FAST8_WIDTH INT32_WIDTH
#define INT_FAST16_WIDTH INT32_WIDTH
#define INT_FAST32_WIDTH INT32_WIDTH
#define INT_FAST64_WIDTH INT64_WIDTH
#define UINT_FAST8_WIDTH INT32_WIDTH
#define UINT_FAST16_WIDTH INT32_WIDTH
#define UINT_FAST32_WIDTH INT32_WIDTH
#define UINT_FAST64_WIDTH INT64_WIDTH
#define INT_FAST8_MIN INT32_MIN
#define INT_FAST16_MIN INT32_MIN
#define INT_FAST32_MIN INT32_MIN
#define INT_FAST64_MIN INT64_MIN
#define INT_FAST8_MAX INT32_MAX
#define INT_FAST16_MAX INT32_MAX
#define INT_FAST32_MAX INT32_MAX
#define INT_FAST64_MAX INT64_MAX
#define UINT_FAST8_MAX UINT32_MAX
#define UINT_FAST16_MAX UINT32_MAX
#define UINT_FAST32_MAX UINT32_MAX
#define UINT_FAST64_MAX UINT64_MAX
#define INTPTR_WIDTH INT64_WIDTH
#define UINTPTR_WIDTH UINT64_WIDTH
#define INTPTR_MIN INT64_MIN
#define INTPTR_MAX INT64_MAX
#define UINTPTR_MAX UINT64_MAX
#define INTMAX_WIDTH INT64_WIDTH
#define UINTMAX_WIDTH UINT64_WIDTH
#define INTMAX_MIN INT64_MIN
#define INTMAX_MAX INT64_MAX
#define UINTMAX_MAX UINT64_MAX
#define INT8_C(lit) lit
#define INT16_C(lit) lit
#define INT32_C(lit) lit
#if defined(_WIN32)
#define INT64_C(lit) lit ## ll
#else
#define INT64_C(lit) lit # l
#endif
#define UINT8_C(lit) lit
#define UINT16_C(lit) lit
#define UINT32_C(lit) lit
#if defined(_WIN32)
#define UINT64_C(lit) lit ## ull
#endif
#if __STDC_WANT_LIB_EXT1__ == 1
#if defined(_WIN32)
#define RSIZE_MAX 0xffffffffffffull;
#else
#define RSIZE_MAX 0xfffffffffffful;
#endif
#endif

View File

@ -1,137 +0,0 @@
#pragma once
#include <stdarg.h>
// 7.23.3 p.2: Header version
#define __STDC_VERSION_STDIO_H__ 202311L
// 7.23.3 p.3: Types
#if defined(_WIN32)
typedef unsigned long long size_t;
#else
typedef unsigned long size_t;
#endif
typedef struct FILE FILE;
typedef struct {
unsigned long long offset;
union {
unsigned short leftover;
unsigned short high_surrogate;
} mbstate;
} fpos_t;
// 7.23.3 p.4: Macros
#if !defined(NULL)
#define NULL ((void *)0)
#endif
#define _IONBF 0
#define _IOFBF 1
#define _IOLBF 2
#define BUFSIZ 512
#define EOF (-1)
#define FOPEN_MAX 32
#ifdef _os_win
#define FILENAME_MAX 260
#else
#define FILENAME_MAX 4096
#endif
#define _PRINTF_NAN_LEN_MAX 20
#define L_tmpnam FILENAME_MAX
#define SEEK_SET 0
#define SEEK_CUR 1
#define SEEK_END 2
#ifdef _os_win
#define TMP_MAX SHORT_MAX
#else
#define TMP_MAX INT_MAX
#endif
#define stdout _internal_stdout
#define stderr _internal_stderr
#define stdin _internal_stdin
extern FILE *_internal_stdout;
extern FILE *_internal_stderr;
extern FILE *_internal_stdin;
// File manipulation
int remove(const char *filename);
int rename(const char *oldname, const char *newname);
// Opening and closing files
char *tmpnam(char *s);
FILE *tmpfile(void);
FILE *fopen (const char *restrict filename, const char *restrict mode);
FILE *freopen(const char *restrict filename, const char *restrict mode, FILE *restrict stream);
int fclose (FILE *stream);
// I/O buffering control
void setbuf (FILE *restrict stream, char *restrict buf);
int setvbuf (FILE *restrict stream, char *restrict buf, int mode, size_t size);
int fflush (FILE *stream);
// String formatted print
int vsnprintf(char *restrict s, size_t n, const char *restrict format, va_list arg);
int vsprintf (char *restrict s, const char *restrict format, va_list arg);
int snprintf (char *restrict s, size_t n, const char *restrict format, ...);
int sprintf (char *restrict s, const char *restrict format, ...);
// File formatted print
int vfprintf (FILE *restrict stream, const char *restrict format, va_list arg);
int fprintf (FILE *restrict stream, const char *restrict format, ...);
int vprintf (const char *restrict format, va_list arg);
int printf (const char *restrict format, ...);
// String formatted scan
int vsscanf(const char *restrict s, const char *restrict format, va_list arg);
int vscanf (const char *restrict format, va_list arg);
int sscanf (const char *restrict s, const char *restrict format, ...);
// String formatted scan
int vfscanf(FILE *restrict stream, const char *restrict format, va_list arg);
int fscanf (FILE *restrict stream, const char *restrict format, ...);
int scanf (const char *restrict format, ...);
// File reading
#define getc fgetc
int fgetc (FILE *stream);
int getchar(void);
int ungetc (int c, FILE *stream);
char *fgets (char *restrict s, int n, FILE *restrict stream);
size_t fread (void *restrict ptr, size_t size, size_t nmemb, FILE *restrict stream);
// File writing
#define putc fputc
int fputc (int c, FILE *stream);
int putchar(int c);
int fputs (const char *restrict s, FILE *restrict stream);
int puts (const char *s);
size_t fwrite (const void *restrict ptr, size_t size, size_t nmemb, FILE *restrict stream);
int fgetpos (FILE *restrict stream, fpos_t *restrict pos);
int fseek (FILE *stream, long int offset, int whence);
int fsetpos (FILE *stream, const fpos_t *pos);
long int ftell (FILE *stream);
void rewind (FILE *stream);
void clearerr(FILE *stream);
int feof (FILE *stream);
int ferror (FILE *stream);
void perror (const char *s);
#if __STDC_WANT_LIB_EXT1__ == 1
#define L_tmpnam_s L_tmpnam
#define TMP_MAX_S TMP_MAX
errno_t tmpfile_s(FILE *restrict *restrict streamptr);
errno_t tmpnam_s (char *s, rsize_t maxsize);
#endif

View File

@ -1,132 +0,0 @@
#pragma once
#if defined(_MSC_VER) && !defined(__clang__)
#define _Noreturn __declspec(noreturn)
#endif
#if !defined(__STDC_LIB_EXT1__)
#define __STDC_LIB_EXT1__
#endif
#ifdef __STDC_WANT_SECURE_LIB__
#if !defined(__STDC_WANT_LIB_EXT1__)
#define __STDC_WANT_LIB_EXT1__ 1
#endif
#endif
#if !defined(NULL)
#define NULL ((void *)0)
#endif
#define EXIT_SUCCESS 0
#define EXIT_FAILURE 1
#if defined(_WIN32)
typedef unsigned long long size_t;
typedef unsigned short wchar_t;
#else
typedef unsigned long size_t;
typedef int wchar_t;
#endif
typedef struct div_t {
int quot;
int rem;
} div_t;
typedef struct ldiv_t {
long quot;
long rem;
} ldiv_t;
typedef struct lldiv_t {
long long quot;
long long rem;
} lldiv_t;
#define EXIT_FAILURE 1
#define EXIT_SUCCESS 0
#define RAND_MAX 65536
#define MB_CUR_MAX 5
// Microsoft extension, COUNTOF(x) counts array elements
#ifndef COUNTOF
#define COUNTOF(...) (sizeof(__VA_ARGS__) / sizeof((__VA_ARGS__)[0]))
#endif
// Some number stuff
int abs (int i);
long labs (long i);
long long llabs(long long i);
div_t div (int numer, int denom);
ldiv_t ldiv (long numer, long denom);
lldiv_t lldiv(long long numer, long long denom);
// String conversion routines
double atof (const char *nptr);
int atoi (const char *nptr);
long atol (const char *nptr);
long long atoll (const char *nptr);
double strtod (const char *restrict nptr, char **restrict endptr);
float strtof (const char *restrict nptr, char **restrict endptr);
long double strtold (const char *restrict nptr, char **restrict endptr);
long strtol (const char *restrict nptr, char **restrict endptr, int base);
long long strtoll (const char *restrict nptr, char **restrict endptr, int base);
unsigned long strtoul (const char *restrict nptr, char **restrict endptr, int base);
unsigned long long strtoull(const char *restrict nptr, char **restrict endptr, int base);
char *itoa(int value, char *str, int base);
// PRNG
int rand (void);
void srand(unsigned int seed);
// Memory management functions
void *malloc (size_t size);
void *calloc (size_t nmemb, size_t size);
void *aligned_alloc(size_t align, size_t size);
void *realloc (void *ptr, size_t size);
void free (void *ptr);
// Communication with environment
_Noreturn void abort (void);
_Noreturn void quick_exit (int status);
_Noreturn void _Exit (int status);
_Noreturn void exit (int status);
int atexit (void (*func)(void));
int at_quick_exit(void (*func)(void));
char *getenv (const char *name);
int system (const char *string);
const void *bsearch(
const void *key,
const void *base,
size_t nmemb,
size_t size,
int (*compar)(const void *, const void *)
);
void qsort(
void *base,
size_t nmemb,
size_t size,
int (*compar)(const void *, const void *)
);
// Multibyte strings
int mblen (const char *s, size_t n);
int mbtowc (wchar_t *restrict pwc, const char *restrict s, size_t n);
size_t mbstowcs(wchar_t *restrict pwcs, const char *restrict s, size_t n);
int wctomb (char *s, wchar_t wchar);
size_t wcstombs(char *restrict s, const wchar_t *restrict pwcs, size_t n);
// #ifdef __STDC_WANT_LIB_EXT1__
// typedef void (*constraint_handler_t)(const char * restrict msg, void * restrict ptr, errno_t error);
// constraint_handler_t set_constraint_handler_s(constraint_handler_t handler);
// void abort_handler_s(const char * restrict msg, void * restrict ptr, errno_t error);
// void ignore_handler_s(const char * restrict msg, void * restrict ptr, errno_t error);
// errno_t getenv_s(size_t * restrict len, char * restrict value, rsize_t maxsize, const char * restrict name);
// #endif

View File

@ -1,6 +0,0 @@
#pragma once
#if !defined(noreturn)
#define noreturn _Noreturn
#endif

View File

@ -1,91 +0,0 @@
#pragma once
#if !defined(NULL)
#define NULL ((void *)0)
#endif
#if defined(_WIN32)
typedef unsigned long long size_t;
#else
typedef unsigned long size_t;
#endif
#if !defined(__STDC_LIB_EXT1__)
#define __STDC_LIB_EXT1__
typedef int errno_t;
typedef size_t rsize_t;
#endif
#if __STDC_WANT_SECURE_LIB__ == 1
#if !defined(__STDC_WANT_LIB_EXT1__)
#define __STDC_WANT_LIB_EXT1__ 1
#endif
#endif
#if !defined(__STDC_ALLOC_LIB__)
#define __STDC_ALLOC_LIB__
#endif
size_t strlen(const char *s);
char *strerror(int errnum);
// Copying
void *memset (void *s, int c, size_t n);
void *memmove (void *s1, const void *s2, size_t n);
void *memcpy (void *restrict s1, const void *restrict s2, size_t n);
char *strncpy (char *restrict s1, const char *restrict s2, size_t n);
char *strcpy (char *restrict s1, const char *restrict s2);
// Concat
char *strncat (char *restrict s1, const char *restrict s2, size_t n);
char *strcat (char *restrict s1, const char *restrict s2);
// Comparison
int memcmp (const void *s1, const void *s2, size_t n);
int strncmp (const char *s1, const char *s2, size_t n);
int strcmp (const char *s1, const char *s2);
// Collation/Localisation thingy
int strcoll (const char *s1, const char *s2);
size_t strxfrm (char *restrict s1, const char *restrict s2, size_t n);
// Tokenization and related stuff
void *memchr (const void *str, int c, size_t n);
char *strchr (const char *str, int c);
size_t strcspn(const char *str, const char *s);
char *strpbrk(const char *str, const char *s);
char *strrchr(const char *str, int c);
size_t strspn (const char *str, const char *s);
char *strstr (const char *str, const char *s);
char *strtok (char *restrict str, const char *restrict s);
// Linux extension: reentrant strtok
char *strtok_r(char *restrict s1, const char *restrict s2, char **restrict ctx);
// Extension 1
#if __STDC_WANT_LIB_EXT1__ == 1
size_t strnlen_s(const char *str, size_t strsz);
// Safe memory copies
errno_t memset_s (void *s, rsize_t smax, int c, rsize_t n);
errno_t memmove_s(void *s1, rsize_t s1max, const void *s2, rsize_t n);
errno_t memcpy_s (void *restrict s1, rsize_t s1max, const void *restrict s2, rsize_t n);
errno_t strncpy_s(char *restrict s1, rsize_t s1max, const char *restrict s2, rsize_t n);
errno_t strcpy_s (char *restrict s1, rsize_t s1max, const char *restrict s2);
// Safe concat et strtok
errno_t strcat_s (char *restrict s1, rsize_t s1max, const char *restrict s2);
errno_t strncat_s(char *restrict s1, rsize_t s1max, const char *restrict s2, rsize_t n);
char *strtok_s(char *restrict s1, rsize_t *restrict s1max, const char *restrict s2, char **restrict ptr);
// Safe error strings
errno_t strerror_s(char *s, rsize_t maxsize, errno_t errnum);
size_t strerrorlen_s(errno_t errnum);
#endif
// Extension 2
#if __STDC_WANT_LIB_EXT2__ == 1
char *strdup(const char *str1);
#endif

View File

@ -1,101 +0,0 @@
#pragma once
#include <math.h>
#define _tg_is_ld(x) (sizeof(x) == sizeof(long double))
#define _tg_is_d(x) (sizeof(x) == sizeof(double))
#define _tg_is_ld2(x,y) (_tg_is_ld(x) || _tg_is_ld(y))
#define _tg_is_d2(x,y) (_tg_is_d (x) || _tg_is_d (y))
#define _tg_is_ld3(x,y,z) (_tg_is_ld(x) || _tg_is_ld(y) || _tg_is_ld(z))
#define _tg_is_d3(x,y,z) (_tg_is_d (x) || _tg_is_d (y) || _tg_is_d (z))
#define _tg_func1(func,x) ( _tg_is_ld(x) ? (func ## l)(x) \
: _tg_is_d(x) ? (func)(x) \
: (func ## f)(x) )
#define _tg_func1p(func,x,p) ( _tg_is_ld(x) ? (func ## l)(x,p) \
: _tg_is_d(x) ? (func)(x,p) \
: (func ## f)(x,p) )
#define _tg_func2(func,x,y) ( _tg_is_ld2(x,y) ? (func ## l)(x,y) \
: _tg_is_d2(x,y) ? (func)(x,y) \
: (func ## f)(x,y) )
#define _tg_func2p(func,x,y,p) ( _tg_is_ld2(x,y) ? (func ## l)(x,y,p) \
: _tg_is_d2(x,y) ? (func)(x,y,p) \
: (func ## f)(x,y,p) )
#define _tg_func3(func,x,y,z) ( _tg_is_ld3(x,y,z) ? (func ## l)(x,y,z) \
: _tg_is_d3(x,y,z) ? (func)(x,y,z) \
: (func ## f)(x,y,z) )
#define cos(x) _tg_func1(cos, x)
#define sin(x) _tg_func1(sin, x)
#define tan(x) _tg_func1(tan, x)
#define acos(x) _tg_func1(acos, x)
#define asin(x) _tg_func1(asin, x)
#define atan(x) _tg_func1(atan, x)
#define atan2(x,y) _tg_func2(atan2, x, y)
#define cosh(x) _tg_func1(cosh, x)
#define sinh(x) _tg_func1(sinh, x)
#define tanh(x) _tg_func1(tanh, x)
#define acosh(x) _tg_func1(acosh, x)
#define asinh(x) _tg_func1(asinh, x)
#define atanh(x) _tg_func1(atanh, x)
#define exp(x) _tg_func1(exp, x)
#define exp2(x) _tg_func1(exp2, x)
#define expm1(x) _tg_func1(expm1, x)
#define pow(x,y) _tg_func2(pow, x, y)
#define log(x,y) _tg_func2(log, x, y)
#define sqrt(x) _tg_func1(sqrt, x)
#define cbrt(x) _tg_func1(cbrt, x)
#define hypot(x,y) _tg_func2(hypot, x, y)
#define log10(x) _tg_func1(log10, x)
#define log1p(x) _tg_func1(log1p, x)
#define log2(x) _tg_func1(log2, x)
#define logb(x) _tg_func1(logb, x)
#define ilogb(x) _tg_func1(ilogb, x)
#define ceil(x) _tg_func1(ceil, x)
#define floor(x) _tg_func1(floor, x)
#define trunc(x) _tg_func1(trunc, x)
#define llrint(x) _tg_func1(llrint, x)
#define lrint(x) _tg_func1(lrint, x)
#define rint(x) _tg_func1(rint, x)
#define llround(x) _tg_func1(llround, x)
#define lround(x) _tg_func1(lround, x)
#define round(x) _tg_func1(round, x)
#define nearbyint(x) _tg_func1(nearbyint, x)
#define erf(x) _tg_func1(erf, x)
#define erfc(x) _tg_func1(erfc, x)
#define tgamma(x) _tg_func1(tgamma, x)
#define lgamma(x) _tg_func1(lgamma, x)
#define fabs(x) _tg_func1(fabs, x)
#define fdim(x,y) _tg_func2(fdim, x, y)
#define fmax(x,y) _tg_func2(fmax, x, y)
#define fmin(x,y) _tg_func2(fmin, x, y)
#define fmod(x,y) _tg_func2(fmod, x, y)
#define remainder(x,y) _tg_func2(remainder, x, y)
#define remquo(x,y,p) _tg_func2p(remquo, x, y, p)
#define fma(x,y,z) _tg_func3(fma, x, y, z)
#define copysign(x,y) _tg_func2(copysign, x, y)
#define frexp(x,p) _tg_func1p(frexp, x, p)
#define ldexp(x,p) _tg_func1p(ldexp, x, p)
#define modf(x,p) _tg_func1p(modf, x, p)
#define scalbn(x,p) _tg_func1p(scalbn, x, p)
#define scalbln(x,p) _tg_func1p(scalbln, x, p)
#define nextafter(x,y) _tg_func2(nextafter, x, y)
#define nexttoward(x,y) _tg_func2(nexttoward, x, y)

View File

@ -1,89 +0,0 @@
#pragma once
// Note(bumbread): some of the macros and types are platform-dependent
// and can be found in os_win/ subfolder.
#if defined(_WIN32)
#include "os_win/threads_types.h"
#else
#error "Not implemented"
#endif
// 7.28.1 p.3: Macros
#define TSS_DTOR_ITERATIONS 32
// TODO(bumbread): check the spec for whether thread_local needs to be declared
// in threads.h
#define thread_local _Thread_local
// 7.28.1 p.4: Types
#if !defined(_timespec_defined)
#define _timespec_defined
typedef unsigned long long time_t;
struct timespec {
time_t tv_sec;
long tv_nsec;
};
#endif
typedef void(*tss_dtor_t) (void*);
typedef int (*thrd_start_t)(void*);
// 7.28.1 p.5: Enumeration constants
enum {
mtx_plain = 0,
mtx_recursive = 1,
mtx_timed = 2,
};
enum {
thrd_success,
thrd_timedout,
thrd_busy,
thrd_error,
thrd_nomem
};
// Thread functions
thrd_t thrd_current(void);
int thrd_create (thrd_t *thr, thrd_start_t func, void *arg);
int thrd_detach (thrd_t thr);
int thrd_equal (thrd_t thr0, thrd_t thr1);
int thrd_join (thrd_t thr, int *res);
void thrd_yield (void);
int thrd_sleep(
const struct timespec *duration,
struct timespec *remaining
);
_Noreturn void thrd_exit(int res);
// Mutex functions
void mtx_destroy (mtx_t *mtx);
int mtx_init (mtx_t *mtx, int type);
int mtx_unlock (mtx_t *mtx);
int mtx_trylock (mtx_t *mtx);
int mtx_lock (mtx_t *mtx);
int mtx_timedlock(
mtx_t *restrict mtx,
const struct timespec *restrict ts
);
// Thread-local storage functions
int tss_create(tss_t *key, tss_dtor_t dtor);
void tss_delete(tss_t key);
void *tss_get (tss_t key);
int tss_set (tss_t key, void *val);
// Condition functions
int cnd_init (cnd_t *cond);
int cnd_broadcast(cnd_t *cond);
void cnd_destroy (cnd_t *cond);
int cnd_signal (cnd_t *cond);
int cnd_wait (cnd_t *cond, mtx_t *mtx);
int cnd_timedwait(cnd_t *restrict cond, mtx_t *restrict mtx, const struct timespec *restrict ts);
// Call once
void call_once(once_flag *flag, void (*func)(void));

View File

@ -1,78 +0,0 @@
#pragma once
// 7.29.1 p.2: Macros
#define __STDC_VERSION_TIME_H__ 202311L
#if !defined(NULL)
#define NULL ((void *)0)
#endif
#define CLOCKS_PER_SEC ((clock_t)1000000)
#define TIME_UTC 1
#define TIME_MONOTONIC 2
#define TIME_ACTIVE 3
#define TIME_THREAD_ACTIVE 4
// 7.29.1 p.4: Types
#if defined(_WIN32)
typedef unsigned long long size_t;
#else
typedef unsigned long size_t;
#endif
typedef unsigned long long clock_t;
typedef unsigned long long time_t;
#if !defined(_timespec_defined)
#define _timespec_defined
struct timespec {
time_t tv_sec;
long tv_nsec;
};
#endif
#if !defined(_tm_defined)
#define _tm_defined
struct tm {
int tm_sec;
int tm_min;
int tm_hour;
int tm_mon;
int tm_mday;
int tm_year;
int tm_wday;
int tm_yday;
int tm_isdst;
};
#endif
// Basic timer functions
clock_t clock(void);
time_t time(time_t *timer);
double difftime(time_t time1, time_t time0);
// Human-readable time functions
time_t mktime(struct tm *timeptr);
struct tm *gmtime(const time_t *timer);
struct tm *localtime(const time_t *timer);
// Timespec functions
int timespec_get(struct timespec *ts, int base);
int timespec_getres(struct timespec *ts, int base);
// Time formatting functions
char *asctime(const struct tm *timeptr);
char *ctime(const time_t *timer);
size_t strftime(char *restrict str, size_t sz, const char *restrict fmt, const struct tm *restrict time);
#ifdef __STDC_WANT_LIB_EXT1__
errno_t asctime_s(char *s, rsize_t maxsize, const struct tm *timeptr);
errno_t ctime_s(char *s, rsize_t maxsize, const time_t *timer);
struct tm *gmtime_s(const time_t * restrict timer, struct tm * restrict result);
struct tm *localtime_s(const time_t * restrict timer, struct tm * restrict result);
#endif

View File

@ -1,48 +0,0 @@
#pragma once
#if defined(_WIN32)
typedef unsigned long long size_t;
#else
typedef unsigned long size_t;
#endif
#if !defined(_mbstate_t_defined)
#define _mbstate_t_defined
typedef struct mbstate_t mbstate_t;
struct mbstate_t {
union {
unsigned short leftover;
unsigned short high_surrogate;
};
};
#endif
typedef unsigned short char16_t;
typedef unsigned int char32_t;
size_t mbrtoc16(
char16_t *restrict pc16,
char const *restrict s,
size_t n,
mbstate_t *restrict ps
);
size_t c16rtomb(
char *restrict s,
char16_t c16,
mbstate_t *restrict ps
);
size_t mbrtoc32(
char32_t *restrict pc32,
char const *restrict s,
size_t n,
mbstate_t *restrict ps
);
size_t c32rtomb(
char *restrict s,
char32_t c32,
mbstate_t *restrict ps
);

View File

@ -1,187 +0,0 @@
#pragma once
#include <locale.h>
#include <stdarg.h>
#if !defined(WEOF)
#define WEOF -1
#endif
#if !defined(NULL)
#define NULL ((void *)0)
#endif
#if defined(_WIN32)
#if !defined(WCHAR_MIN)
#define WCHAR_MIN 0x0000
#endif
#if !defined(WCHAR_MAX)
#define WCHAR_MAX 0xffff
#endif
typedef unsigned short wchar_t;
#else
#if !defined(WCHAR_MIN)
#define WCHAR_MIN -0x80000000
#endif
#if !defined(WCHAR_MAX)
#define WCHAR_MAX +0x7fffffff
#endif
typedef int wchar_t;
#endif
typedef int wint_t;
typedef int wint_t;
typedef int (*wctrans_t)(wint_t wc);
typedef int (*wctype_t)(wint_t wc);
#if !defined(_mbstate_t_defined)
#define _mbstate_t_defined
typedef struct mbstate_t mbstate_t;
struct mbstate_t {
union {
unsigned short leftover;
unsigned short high_surrogate;
};
};
#endif
#if !defined(_tm_defined)
#define _tm_defined
struct tm {
int tm_sec;
int tm_min;
int tm_hour;
int tm_mon;
int tm_mday;
int tm_year;
int tm_wday;
int tm_yday;
int tm_isdst;
};
#endif
typedef struct FILE FILE;
// String length
size_t wcslen(const wchar_t *s);
// Copying
wchar_t *wmemset (wchar_t *s, wchar_t c, size_t n);
wchar_t *wmemmove(wchar_t *s1, wchar_t const *s2, size_t n);
wchar_t *wmemcpy (wchar_t *restrict s1, wchar_t const *restrict s2, size_t n);
wchar_t *wcsncpy (wchar_t *restrict s1, wchar_t const *restrict s2, size_t n);
wchar_t *wcscpy (wchar_t *restrict s1, wchar_t const *restrict s2);
// Concat
wchar_t *wcscat (wchar_t *restrict s1, wchar_t const *restrict s2);
wchar_t *wcsncat(wchar_t *restrict s1, wchar_t const *restrict s2, size_t n);
// Comparison
int wcscmp (wchar_t const *s1, wchar_t const *s2);
int wcsncmp(wchar_t const *s1, wchar_t const *s2, size_t n);
int wmemcmp(wchar_t const *s1, wchar_t const *s2, size_t n);
// Localization
int wcscoll (wchar_t const *s1, wchar_t const *s2);
size_t wcsxfrm (wchar_t *restrict s1, wchar_t const *restrict s2, size_t n);
// Tokenization and stuff
wchar_t *wmemchr(wchar_t const *s, wchar_t c, size_t n);
wchar_t *wcschr (wchar_t const *s, wchar_t c);
wchar_t *wcsrchr(wchar_t const *s, wchar_t c);
wchar_t *wcspbrk(wchar_t const *s1, wchar_t const *s2);
size_t wcscspn(wchar_t const *s1, wchar_t const *s2);
size_t wcsspn (wchar_t const *s1, wchar_t const *s2);
wchar_t *wcsstr (wchar_t const *s1, wchar_t const *s2);
wchar_t *wcstok (wchar_t *restrict s1, wchar_t const *restrict s2, wchar_t **restrict ptr);
// Formatted print
int vfwprintf(FILE *restrict stream, const wchar_t *restrict format, va_list arg);
int fwprintf (FILE *restrict stream, const wchar_t *restrict format, ...);
int vswprintf(wchar_t *restrict s, size_t n, const wchar_t *restrict format, va_list arg);
int swprintf (wchar_t *restrict s, size_t n, const wchar_t *restrict format, ...);
int vwprintf (wchar_t const *restrict format, va_list arg);
int wprintf (wchar_t const *restrict format, ...);
// Formatted scan
int vfwscanf(FILE *restrict stream, const wchar_t *restrict format, va_list arg);
int fwscanf (FILE *restrict stream, const wchar_t *restrict format, ...);
int vswscanf(const wchar_t *restrict s, const wchar_t *restrict format, va_list arg);
int swscanf (const wchar_t *restrict s, const wchar_t *restrict format, ...);
int vwscanf (const wchar_t *restrict format, va_list arg);
int wscanf (const wchar_t *restrict format, ...);
// File reading
wint_t fgetwc(FILE *stream);
wchar_t *fgetws(wchar_t *restrict s, int n, FILE *restrict stream);
wint_t getwc(FILE *stream);
wint_t getwchar(void);
wint_t ungetwc(wint_t c, FILE *stream);
wint_t fputwc(wchar_t c, FILE *stream);
// File writing
int fputws(const wchar_t *restrict s, FILE *restrict stream);
wint_t putwc(wchar_t c, FILE *stream);
wint_t putwchar(wchar_t c);
// Switch stream mode to wide
int fwide(FILE *stream, int mode);
// Float conversions
double wcstod (wchar_t const *restrict nptr, wchar_t **restrict endptr);
float wcstof (wchar_t const *restrict nptr, wchar_t **restrict endptr);
// Integer conversions
long double wcstold (wchar_t const *restrict nptr, wchar_t **restrict endptr);
long int wcstol (wchar_t const *restrict nptr, wchar_t **restrict endptr, int base);
long long int wcstoll (wchar_t const *restrict nptr, wchar_t **restrict endptr, int base);
unsigned long int wcstoul (wchar_t const *restrict nptr, wchar_t **restrict endptr, int base);
unsigned long long int wcstoull(wchar_t const *restrict nptr, wchar_t **restrict endptr, int base);
// Character conversions
wint_t btowc(int c);
int wctob(wint_t c);
// Ftime conversion
size_t wcsftime(wchar_t *restrict s, size_t maxsize, const wchar_t *restrict format, const struct tm *restrict timeptr);
// Multibyte conversions
int mbsinit (mbstate_t const *ps);
size_t mbrlen (char const *restrict s, size_t n, mbstate_t *restrict ps);
size_t mbrtowc (wchar_t *restrict pwc, char const *restrict s, size_t n, mbstate_t *restrict ps);
size_t mbsrtowcs(wchar_t *restrict dst, char const **restrict src, size_t len, mbstate_t *restrict ps);
size_t wcrtomb (char *restrict s, wchar_t wc, mbstate_t *restrict ps);
size_t wcsrtombs(char *restrict dst, wchar_t const **restrict src, size_t len, mbstate_t *restrict ps);
#ifdef __STDC_WANT_LIB_EXT1__
int vfwprintf_s (FILE *restrict stream, const wchar_t *restrict format, va_list arg);
int fwprintf_s (FILE *restrict stream, const wchar_t *restrict format, ...);
int vsnwprintf_s(wchar_t *restrict s, rsize_t n, const wchar_t *restrict format, va_list arg);
int vswprintf_s (wchar_t *restrict s, rsize_t n, const wchar_t *restrict format, va_list arg);
int snwprintf_s (wchar_t *restrict s, rsize_t n, const wchar_t *restrict format, ...);
int swprintf_s (wchar_t *restrict s, rsize_t n, const wchar_t *restrict format, ...);
int vwprintf_s (wchar_t const *restrict format, va_list arg);
int wprintf_s (wchar_t const *restrict format, ...);
int vfwscanf_s(FILE *restrict stream, const wchar_t *restrict format, va_list arg);
int fwscanf_s (FILE *restrict stream, const wchar_t *restrict format, ...);
int vswscanf_s(const wchar_t *restrict s, const wchar_t *restrict format, va_list arg);
int swscanf_s (const wchar_t *restrict s, const wchar_t *restrict format, ...);
int vwscanf_s (const wchar_t *restrict format, va_list arg);
int wscanf_s (const wchar_t *restrict format, ...);
errno_t wcscpy_s (wchar_t *restrict s1, rsize_t s1max, const wchar_t *restrict s2);
errno_t wcsncpy_s (wchar_t *restrict s1, rsize_t s1max, const wchar_t *restrict s2, rsize_t n);
errno_t wmemcpy_s (wchar_t *restrict s1, rsize_t s1max, const wchar_t *restrict s2, rsize_t n);
errno_t wmemmove_s(wchar_t *s1, rsize_t s1max, const wchar_t *s2, rsize_t n);
errno_t wcscat_s (wchar_t *restrict s1, rsize_t s1max, const wchar_t *restrict s2);
errno_t wcsncat_s (wchar_t *restrict s1, rsize_t s1max, const wchar_t *restrict s2, rsize_t n);
wchar_t *wcstok_s (wchar_t *restrict s1, rsize_t *restrict s1max, const wchar_t *restrict s2, wchar_t **restrict ptr);
size_t wcsnlen_s (const wchar_t *s, size_t maxsize);
errno_t wcrtomb_s (size_t *restrict retval, char *restrict s, rsize_t smax, wchar_t wc, mbstate_t *restrict ps);
errno_t mbsrtowcs_s(size_t *restrict retval, wchar_t *restrict dst, rsize_t dstmax, const char **restrict src, rsize_t len, mbstate_t *restrict ps);
errno_t wcsrtombs_s(size_t *restrict retval, char *restrict dst, rsize_t dstmax, const wchar_t **restrict src, rsize_t len, mbstate_t *restrict ps);
#endif

View File

@ -1,29 +0,0 @@
#pragma once
typedef int wint_t;
typedef int (*wctrans_t)(wint_t wc);
typedef int (*wctype_t)(wint_t wc);
#if !defined(WEOF)
#define WEOF 0
#endif
int iswalnum(wint_t wc);
int iswalpha(wint_t wc);
int iswblank(wint_t wc);
int iswcntrl(wint_t wc);
int iswdigit(wint_t wc);
int iswgraph(wint_t wc);
int iswlower(wint_t wc);
int iswprint(wint_t wc);
int iswpunct(wint_t wc);
int iswspace(wint_t wc);
int iswupper(wint_t wc);
int iswxdigit(wint_t wc);
int iswctype(wint_t wc, wctype_t desc);
wctype_t wctype(const char *property);
wint_t towlower(wint_t wc);
wint_t towupper(wint_t wc);
wint_t towctrans(wint_t wc, wctrans_t desc);
wctrans_t wctrans(const char *property);

13
license Normal file
View File

@ -0,0 +1,13 @@
Zero-Clause BSD
=============
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED “AS IS” AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE
FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE

View File

@ -38,23 +38,57 @@ This library is supposed to be extensible to other platforms, meaning that
you can write an OS layer for another OS and use the rest of the CRT
functionality.
## Building & Usage
## Building ciabatta
Building ciabatta with MSVC is not supported. The only compiler that the
library have been compiled and tested with is clang.
Note that the library can only be used with clang
1. Run ./build.cmd to compile ciabatta
- (Optionally) Run `./test crt` to make sure there are no errors
2. Grab the following files into your project's directory:
- The `./include` folder
- The `./ciabatta.lib` archive file
- The `./utf8.obj` object file
3. Add the following flags to your compilation command:
`-I ./include utf8.obj -nostdlib -mfma`
4. Don't forget to link to the following libraries:
`-lciabatta.lib`
### Building on windows
Run ./build.ps1 to compile ciabatta
- (Optionally) Run `./test crt` to make sure there are no errors
### Building and using on linux
There are two options: Use ciabatta as a shared library or as a static
library.
Run ./build.sh to compile ciabatta
- If you wish to use shared library instead add -shared option to the build script
## Usage
Grab the following files into your project's (or any other) directory:
- The `./include` folder
- The `.lib` folder
- (Windows only) The `utf8` folder
In order to compile your project with ciabatta see the following sections
### Compiling with ciabatta on windows
1. Add the following flags to your compilation command:
`-nostdlib -I ./include utf8.obj -mfma`
2. Link to the following libraries:
`-l ./lib/ciabatta.lib`
**Note:** The `include` folder refers to the folder you copied from ciabatta. Set the path to it accordingly.
### Compiling with ciabatta on linux
1. In case of static linking:
1. Add the following flags to your compilation command:
`-nostdlib -static -I ./include`
2. Link to the following libraries
`./lib/ciabatta.a`
2. In case of dynamic linking:
1. Add the following flags to your compilation command:
`-nostdlib -no-pie -I ./include`
2. Link to the following libraries:
`./lib/ciabatta.so ./lib.ctors.o ./lib.entry.o`
## Contributing
@ -62,4 +96,4 @@ Pull requests welcome and accepted in any form.
## License
TBD
See [the license file](license)

View File

@ -1,78 +1,7 @@
// Standard Headers
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <fenv.h>
#include <float.h>
#include <inttypes.h>
#include <limits.h>
#include <locale.h>
#include <math.h>
#include <signal.h>
#include <stdarg.h>
#include <stdatomic.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <threads.h>
#include <time.h>
#include <uchar.h>
#include <wchar.h>
#include <wctype.h>
#include <cia_definitions.h>
// Intrinsics
#if !defined(__FMA__)
#if !defined(_MSC_VER)
#error "Get a better CPU (the kind that supports FMA) or enable -mfma"
#endif
#endif
// xmmintrin.h depends on mm_malloc.h, which itself includes other CRT headers
// Which introduces compiler errors. Actually does it really matter? I would
// need to check again
#undef __STDC_HOSTED__
// #include <immintrin.h>
#include <xmmintrin.h>
#include "intrin.h"
// Platform-independent functionality
#include "util.c"
#include "math/basic.c"
#include "math/division.c"
#include "math/gen_math.c"
#include "math/bits.c"
#include "math/round.c"
#include "conv/decfloat/decfloat.c"
#include "conv/digits.c"
#include "conv/strpfx.c"
#include "conv/int.c"
#include "conv/float.c"
#include "stdlib/algorithm.c"
#include "stdlib/multibyte.c"
#include "stdlib/random.c"
#include "ctype.c"
#include "errno.c"
#include "fenv.c"
#include "locale.c"
#include "string.c"
#include "uchar.c"
#include "wchar.c"
#include "wctype.c"
// Windows platform functionality
#if defined(CIABATTA_WIN)
#include "os_win/win.h"
#include "os_win/cookie.c"
#include "os_win/assert.c"
#include "os_win/cmdline.c"
#include "os_win/env.c"
#include "os_win/mem.c"
#include "os_win/signal.c"
#include "os_win/file.c"
#include "os_win/thread.c"
#include "os_win/time.c"
#include "os_win/entry.c"
#if os_is_linux()
#include "linux/syscall.c"
#include "linux/entry.c"
#endif

View File

@ -1,319 +0,0 @@
#include "decfloat_table.h"
typedef struct decfloat_t decfloat_t;
struct decfloat_t {
u64 sign;
u64 exponent;
i64 mantissa;
};
#define DOUBLE_MANTISSA_BITS 52
#define DOUBLE_EXPONENT_BITS 11
#define DOUBLE_BIAS 1023
static const char DIGIT_TABLE[200] = {
"00010203040506070809101112131415161718192021222324"
"25262728293031323334353637383940414243444546474849"
"50515253545556575859606162636465666768697071727374"
"75767778798081828384858687888990919293949596979899"
};
static inline u32 pow5Factor(u64 value) {
const u64 m_inv_5 = 14757395258967641293u; // 5 * m_inv_5 = 1 (mod 2^64)
const u64 n_div_5 = 3689348814741910323u; // #{ n | n = 0 (mod 2^64) } = 2^64 / 5
u32 count = 0;
for (;;) {
value *= m_inv_5;
if (value > n_div_5)
break;
++count;
}
return count;
}
// Returns true if value is divisible by 5^p.
static inline bool multipleOfPowerOf5(const u64 value, const u32 p) {
// I tried a case distinction on p, but there was no performance difference.
return pow5Factor(value) >= p;
}
// Returns true if value is divisible by 2^p.
static inline bool multipleOfPowerOf2(const u64 value, const u32 p) {
// __builtin_ctzll doesn't appear to be faster here.
return (value & ((1ull << p) - 1)) == 0;
}
static inline u64 umul128(const u64 a, const u64 b, u64* const productHi) {
return _umul128(a, b, productHi);
}
static inline u64 umulh(const u64 a, const u64 b) {
u64 hi;
umul128(a, b, &hi);
return hi;
}
static inline u64 shiftright128(const u64 lo, const u64 hi, const u32 dist) {
return __shiftright128(lo, hi, (unsigned char) dist);
}
static inline u64 mulShift64(const u64 m, const u64* const mul, const int32_t j) {
// m is maximum 55 bits
u64 high1; // 128
const u64 low1 = umul128(m, mul[1], &high1); // 64
u64 high0; // 64
umul128(m, mul[0], &high0); // 0
const u64 sum = high0 + low1;
if (sum < high0) {
++high1; // overflow into high1
}
return shiftright128(sum, high1, j - 64);
}
static inline u64 mulShiftAll64(const u64 m, const u64* const mul, const int32_t j,
u64* const vp, u64* const vm, const u32 mmShift) {
*vp = mulShift64(4 * m + 2, mul, j);
*vm = mulShift64(4 * m - 1 - mmShift, mul, j);
return mulShift64(4 * m, mul, j);
}
// Returns floor(log_10(2^e)); requires 0 <= e <= 1650.
static inline u32 log10Pow2(const int32_t e) {
// The first value this approximation fails for is 2^1651 which is just greater than 10^297.
return (((u32) e) * 78913) >> 18;
}
// Returns floor(log_10(5^e)); requires 0 <= e <= 2620.
static inline u32 log10Pow5(const int32_t e) {
// The first value this approximation fails for is 5^2621 which is just greater than 10^1832.
return (((u32) e) * 732923) >> 20;
}
// Returns e == 0 ? 1 : ceil(log_2(5^e)); requires 0 <= e <= 3528.
static inline int32_t pow5bits(const int32_t e) {
// This approximation works up to the point that the multiplication overflows at e = 3529.
// If the multiplication were done in 64 bits, it would fail at 5^4004 which is just greater
// than 2^9297.
return (int32_t) (((((u32) e) * 1217359) >> 19) + 1);
}
static inline u32 decimalLength17(const u64 v) {
// This is slightly faster than a loop.
// The average output length is 16.38 digits, so we check high-to-low.
// Function precondition: v is not an 18, 19, or 20-digit number.
// (17 digits are sufficient for round-tripping.)
if (v >= 10000000000000000L) { return 17; }
if (v >= 1000000000000000L) { return 16; }
if (v >= 100000000000000L) { return 15; }
if (v >= 10000000000000L) { return 14; }
if (v >= 1000000000000L) { return 13; }
if (v >= 100000000000L) { return 12; }
if (v >= 10000000000L) { return 11; }
if (v >= 1000000000L) { return 10; }
if (v >= 100000000L) { return 9; }
if (v >= 10000000L) { return 8; }
if (v >= 1000000L) { return 7; }
if (v >= 100000L) { return 6; }
if (v >= 10000L) { return 5; }
if (v >= 1000L) { return 4; }
if (v >= 100L) { return 3; }
if (v >= 10L) { return 2; }
return 1;
}
static inline u64 div5(const u64 x) {
return umulh(x, 0xCCCCCCCCCCCCCCCDu) >> 2;
}
static inline u64 div10(const u64 x) {
return umulh(x, 0xCCCCCCCCCCCCCCCDu) >> 3;
}
static inline u64 div100(const u64 x) {
return umulh(x >> 2, 0x28F5C28F5C28F5C3u) >> 2;
}
static inline u64 div1e8(const u64 x) {
return umulh(x, 0xABCC77118461CEFDu) >> 26;
}
static decfloat_t ieee_to_decimal(u64 sign, u64 ieeeMantissa, u32 ieeeExponent) {
int32_t e2;
u64 m2;
if (ieeeExponent == 0) {
// We subtract 2 so that the bounds computation has 2 additional bits.
e2 = 1 - DOUBLE_BIAS - DOUBLE_MANTISSA_BITS - 2;
m2 = ieeeMantissa;
} else {
e2 = (int32_t) ieeeExponent - DOUBLE_BIAS - DOUBLE_MANTISSA_BITS - 2;
m2 = (1ull << DOUBLE_MANTISSA_BITS) | ieeeMantissa;
}
const bool even = (m2 & 1) == 0;
const bool acceptBounds = even;
// Step 2: Determine the interval of valid decimal representations.
const u64 mv = 4 * m2;
// Implicit bool -> int conversion. True is 1, false is 0.
const u32 mmShift = ieeeMantissa != 0 || ieeeExponent <= 1;
// We would compute mp and mm like this:
// u64 mp = 4 * m2 + 2;
// u64 mm = mv - 1 - mmShift;
// Step 3: Convert to a decimal power base using 128-bit arithmetic.
u64 vr, vp, vm;
int32_t e10;
bool vmIsTrailingZeros = false;
bool vrIsTrailingZeros = false;
if (e2 >= 0) {
// I tried special-casing q == 0, but there was no effect on performance.
// This expression is slightly faster than max(0, log10Pow2(e2) - 1).
const u32 q = log10Pow2(e2) - (e2 > 3);
e10 = (int32_t) q;
const int32_t k = DOUBLE_POW5_INV_BITCOUNT + pow5bits((int32_t) q) - 1;
const int32_t i = -e2 + (int32_t) q + k;
vr = mulShiftAll64(m2, DOUBLE_POW5_INV_SPLIT[q], i, &vp, &vm, mmShift);
if (q <= 21) {
// This should use q <= 22, but I think 21 is also safe. Smaller values
// may still be safe, but it's more difficult to reason about them.
// Only one of mp, mv, and mm can be a multiple of 5, if any.
const u32 mvMod5 = ((u32) mv) - 5 * ((u32) div5(mv));
if (mvMod5 == 0) {
vrIsTrailingZeros = multipleOfPowerOf5(mv, q);
} else if (acceptBounds) {
// Same as min(e2 + (~mm & 1), pow5Factor(mm)) >= q
// <=> e2 + (~mm & 1) >= q && pow5Factor(mm) >= q
// <=> true && pow5Factor(mm) >= q, since e2 >= q.
vmIsTrailingZeros = multipleOfPowerOf5(mv - 1 - mmShift, q);
} else {
// Same as min(e2 + 1, pow5Factor(mp)) >= q.
vp -= multipleOfPowerOf5(mv + 2, q);
}
}
} else {
// This expression is slightly faster than max(0, log10Pow5(-e2) - 1).
const u32 q = log10Pow5(-e2) - (-e2 > 1);
e10 = (int32_t) q + e2;
const int32_t i = -e2 - (int32_t) q;
const int32_t k = pow5bits(i) - DOUBLE_POW5_BITCOUNT;
const int32_t j = (int32_t) q - k;
vr = mulShiftAll64(m2, DOUBLE_POW5_SPLIT[i], j, &vp, &vm, mmShift);
if (q <= 1) {
// {vr,vp,vm} is trailing zeros if {mv,mp,mm} has at least q trailing 0 bits.
// mv = 4 * m2, so it always has at least two trailing 0 bits.
vrIsTrailingZeros = true;
if (acceptBounds) {
// mm = mv - 1 - mmShift, so it has 1 trailing 0 bit iff mmShift == 1.
vmIsTrailingZeros = mmShift == 1;
} else {
// mp = mv + 2, so it always has at least one trailing 0 bit.
--vp;
}
} else if (q < 63) { // TODO(ulfjack): Use a tighter bound here.
// We want to know if the full product has at least q trailing zeros.
// We need to compute min(p2(mv), p5(mv) - e2) >= q
// <=> p2(mv) >= q && p5(mv) - e2 >= q
// <=> p2(mv) >= q (because -e2 >= q)
vrIsTrailingZeros = multipleOfPowerOf2(mv, q);
}
}
// Step 4: Find the shortest decimal representation in the interval of valid representations.
int32_t removed = 0;
uint8_t lastRemovedDigit = 0;
u64 output;
// On average, we remove ~2 digits.
if (vmIsTrailingZeros || vrIsTrailingZeros) {
// General case, which happens rarely (~0.7%).
for (;;) {
const u64 vpDiv10 = div10(vp);
const u64 vmDiv10 = div10(vm);
if (vpDiv10 <= vmDiv10) {
break;
}
const u32 vmMod10 = ((u32) vm) - 10 * ((u32) vmDiv10);
const u64 vrDiv10 = div10(vr);
const u32 vrMod10 = ((u32) vr) - 10 * ((u32) vrDiv10);
vmIsTrailingZeros &= vmMod10 == 0;
vrIsTrailingZeros &= lastRemovedDigit == 0;
lastRemovedDigit = (uint8_t) vrMod10;
vr = vrDiv10;
vp = vpDiv10;
vm = vmDiv10;
++removed;
}
if (vmIsTrailingZeros) {
for (;;) {
const u64 vmDiv10 = div10(vm);
const u32 vmMod10 = ((u32) vm) - 10 * ((u32) vmDiv10);
if (vmMod10 != 0) {
break;
}
const u64 vpDiv10 = div10(vp);
const u64 vrDiv10 = div10(vr);
const u32 vrMod10 = ((u32) vr) - 10 * ((u32) vrDiv10);
vrIsTrailingZeros &= lastRemovedDigit == 0;
lastRemovedDigit = (uint8_t) vrMod10;
vr = vrDiv10;
vp = vpDiv10;
vm = vmDiv10;
++removed;
}
}
if (vrIsTrailingZeros && lastRemovedDigit == 5 && vr % 2 == 0) {
// Round even if the exact number is .....50..0.
lastRemovedDigit = 4;
}
// We need to take vr + 1 if vr is outside bounds or we need to round up.
output = vr + ((vr == vm && (!acceptBounds || !vmIsTrailingZeros)) || lastRemovedDigit >= 5);
} else {
// Specialized for the common case (~99.3%). Percentages below are relative to this.
bool roundUp = false;
const u64 vpDiv100 = div100(vp);
const u64 vmDiv100 = div100(vm);
if (vpDiv100 > vmDiv100) { // Optimization: remove two digits at a time (~86.2%).
const u64 vrDiv100 = div100(vr);
const u32 vrMod100 = ((u32) vr) - 100 * ((u32) vrDiv100);
roundUp = vrMod100 >= 50;
vr = vrDiv100;
vp = vpDiv100;
vm = vmDiv100;
removed += 2;
}
// Loop iterations below (approximately), without optimization above:
// 0: 0.03%, 1: 13.8%, 2: 70.6%, 3: 14.0%, 4: 1.40%, 5: 0.14%, 6+: 0.02%
// Loop iterations below (approximately), with optimization above:
// 0: 70.6%, 1: 27.8%, 2: 1.40%, 3: 0.14%, 4+: 0.02%
for (;;) {
const u64 vpDiv10 = div10(vp);
const u64 vmDiv10 = div10(vm);
if (vpDiv10 <= vmDiv10) {
break;
}
const u64 vrDiv10 = div10(vr);
const u32 vrMod10 = ((u32) vr) - 10 * ((u32) vrDiv10);
roundUp = vrMod10 >= 5;
vr = vrDiv10;
vp = vpDiv10;
vm = vmDiv10;
++removed;
}
// We need to take vr + 1 if vr is outside bounds or we need to round up.
output = vr + (vr == vm || roundUp);
}
const int32_t exp = e10 + removed;
decfloat_t fd;
fd.sign = sign;
fd.exponent = output? exp : 0;
fd.mantissa = output;
return fd;
}
static decfloat_t f64_to_decimal(double d) {
u64 bits = F64_BITS(d);
u64 ieee_exp = F64_BEXP(bits);
u64 ieee_mant = F64_MANT(bits);
u64 sign = bits >> 63;
return ieee_to_decimal(sign, ieee_mant, ieee_exp);
}

View File

@ -1,367 +0,0 @@
// Copyright 2018 Ulf Adams
//
// The contents of this file may be used under the terms of the Apache License,
// Version 2.0.
//
// (See accompanying file LICENSE-Apache or copy at
// http://www.apache.org/licenses/LICENSE-2.0)
//
// Alternatively, the contents of this file may be used under the terms of
// the Boost Software License, Version 1.0.
// (See accompanying file LICENSE-Boost or copy at
// https://www.boost.org/LICENSE_1_0.txt)
//
// Unless required by applicable law or agreed to in writing, this software
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.
#ifndef RYU_D2S_FULL_TABLE_H
#define RYU_D2S_FULL_TABLE_H
// These tables are generated by PrintDoubleLookupTable.
#define DOUBLE_POW5_INV_BITCOUNT 125
#define DOUBLE_POW5_BITCOUNT 125
#define DOUBLE_POW5_INV_TABLE_SIZE 342
#define DOUBLE_POW5_TABLE_SIZE 326
static const uint64_t DOUBLE_POW5_INV_SPLIT[DOUBLE_POW5_INV_TABLE_SIZE][2] = {
{ 1u, 2305843009213693952u }, { 11068046444225730970u, 1844674407370955161u },
{ 5165088340638674453u, 1475739525896764129u }, { 7821419487252849886u, 1180591620717411303u },
{ 8824922364862649494u, 1888946593147858085u }, { 7059937891890119595u, 1511157274518286468u },
{ 13026647942995916322u, 1208925819614629174u }, { 9774590264567735146u, 1934281311383406679u },
{ 11509021026396098440u, 1547425049106725343u }, { 16585914450600699399u, 1237940039285380274u },
{ 15469416676735388068u, 1980704062856608439u }, { 16064882156130220778u, 1584563250285286751u },
{ 9162556910162266299u, 1267650600228229401u }, { 7281393426775805432u, 2028240960365167042u },
{ 16893161185646375315u, 1622592768292133633u }, { 2446482504291369283u, 1298074214633706907u },
{ 7603720821608101175u, 2076918743413931051u }, { 2393627842544570617u, 1661534994731144841u },
{ 16672297533003297786u, 1329227995784915872u }, { 11918280793837635165u, 2126764793255865396u },
{ 5845275820328197809u, 1701411834604692317u }, { 15744267100488289217u, 1361129467683753853u },
{ 3054734472329800808u, 2177807148294006166u }, { 17201182836831481939u, 1742245718635204932u },
{ 6382248639981364905u, 1393796574908163946u }, { 2832900194486363201u, 2230074519853062314u },
{ 5955668970331000884u, 1784059615882449851u }, { 1075186361522890384u, 1427247692705959881u },
{ 12788344622662355584u, 2283596308329535809u }, { 13920024512871794791u, 1826877046663628647u },
{ 3757321980813615186u, 1461501637330902918u }, { 10384555214134712795u, 1169201309864722334u },
{ 5547241898389809503u, 1870722095783555735u }, { 4437793518711847602u, 1496577676626844588u },
{ 10928932444453298728u, 1197262141301475670u }, { 17486291911125277965u, 1915619426082361072u },
{ 6610335899416401726u, 1532495540865888858u }, { 12666966349016942027u, 1225996432692711086u },
{ 12888448528943286597u, 1961594292308337738u }, { 17689456452638449924u, 1569275433846670190u },
{ 14151565162110759939u, 1255420347077336152u }, { 7885109000409574610u, 2008672555323737844u },
{ 9997436015069570011u, 1606938044258990275u }, { 7997948812055656009u, 1285550435407192220u },
{ 12796718099289049614u, 2056880696651507552u }, { 2858676849947419045u, 1645504557321206042u },
{ 13354987924183666206u, 1316403645856964833u }, { 17678631863951955605u, 2106245833371143733u },
{ 3074859046935833515u, 1684996666696914987u }, { 13527933681774397782u, 1347997333357531989u },
{ 10576647446613305481u, 2156795733372051183u }, { 15840015586774465031u, 1725436586697640946u },
{ 8982663654677661702u, 1380349269358112757u }, { 18061610662226169046u, 2208558830972980411u },
{ 10759939715039024913u, 1766847064778384329u }, { 12297300586773130254u, 1413477651822707463u },
{ 15986332124095098083u, 2261564242916331941u }, { 9099716884534168143u, 1809251394333065553u },
{ 14658471137111155161u, 1447401115466452442u }, { 4348079280205103483u, 1157920892373161954u },
{ 14335624477811986218u, 1852673427797059126u }, { 7779150767507678651u, 1482138742237647301u },
{ 2533971799264232598u, 1185710993790117841u }, { 15122401323048503126u, 1897137590064188545u },
{ 12097921058438802501u, 1517710072051350836u }, { 5988988032009131678u, 1214168057641080669u },
{ 16961078480698431330u, 1942668892225729070u }, { 13568862784558745064u, 1554135113780583256u },
{ 7165741412905085728u, 1243308091024466605u }, { 11465186260648137165u, 1989292945639146568u },
{ 16550846638002330379u, 1591434356511317254u }, { 16930026125143774626u, 1273147485209053803u },
{ 4951948911778577463u, 2037035976334486086u }, { 272210314680951647u, 1629628781067588869u },
{ 3907117066486671641u, 1303703024854071095u }, { 6251387306378674625u, 2085924839766513752u },
{ 16069156289328670670u, 1668739871813211001u }, { 9165976216721026213u, 1334991897450568801u },
{ 7286864317269821294u, 2135987035920910082u }, { 16897537898041588005u, 1708789628736728065u },
{ 13518030318433270404u, 1367031702989382452u }, { 6871453250525591353u, 2187250724783011924u },
{ 9186511415162383406u, 1749800579826409539u }, { 11038557946871817048u, 1399840463861127631u },
{ 10282995085511086630u, 2239744742177804210u }, { 8226396068408869304u, 1791795793742243368u },
{ 13959814484210916090u, 1433436634993794694u }, { 11267656730511734774u, 2293498615990071511u },
{ 5324776569667477496u, 1834798892792057209u }, { 7949170070475892320u, 1467839114233645767u },
{ 17427382500606444826u, 1174271291386916613u }, { 5747719112518849781u, 1878834066219066582u },
{ 15666221734240810795u, 1503067252975253265u }, { 12532977387392648636u, 1202453802380202612u },
{ 5295368560860596524u, 1923926083808324180u }, { 4236294848688477220u, 1539140867046659344u },
{ 7078384693692692099u, 1231312693637327475u }, { 11325415509908307358u, 1970100309819723960u },
{ 9060332407926645887u, 1576080247855779168u }, { 14626963555825137356u, 1260864198284623334u },
{ 12335095245094488799u, 2017382717255397335u }, { 9868076196075591040u, 1613906173804317868u },
{ 15273158586344293478u, 1291124939043454294u }, { 13369007293925138595u, 2065799902469526871u },
{ 7005857020398200553u, 1652639921975621497u }, { 16672732060544291412u, 1322111937580497197u },
{ 11918976037903224966u, 2115379100128795516u }, { 5845832015580669650u, 1692303280103036413u },
{ 12055363241948356366u, 1353842624082429130u }, { 841837113407818570u, 2166148198531886609u },
{ 4362818505468165179u, 1732918558825509287u }, { 14558301248600263113u, 1386334847060407429u },
{ 12225235553534690011u, 2218135755296651887u }, { 2401490813343931363u, 1774508604237321510u },
{ 1921192650675145090u, 1419606883389857208u }, { 17831303500047873437u, 2271371013423771532u },
{ 6886345170554478103u, 1817096810739017226u }, { 1819727321701672159u, 1453677448591213781u },
{ 16213177116328979020u, 1162941958872971024u }, { 14873036941900635463u, 1860707134196753639u },
{ 15587778368262418694u, 1488565707357402911u }, { 8780873879868024632u, 1190852565885922329u },
{ 2981351763563108441u, 1905364105417475727u }, { 13453127855076217722u, 1524291284333980581u },
{ 7073153469319063855u, 1219433027467184465u }, { 11317045550910502167u, 1951092843947495144u },
{ 12742985255470312057u, 1560874275157996115u }, { 10194388204376249646u, 1248699420126396892u },
{ 1553625868034358140u, 1997919072202235028u }, { 8621598323911307159u, 1598335257761788022u },
{ 17965325103354776697u, 1278668206209430417u }, { 13987124906400001422u, 2045869129935088668u },
{ 121653480894270168u, 1636695303948070935u }, { 97322784715416134u, 1309356243158456748u },
{ 14913111714512307107u, 2094969989053530796u }, { 8241140556867935363u, 1675975991242824637u },
{ 17660958889720079260u, 1340780792994259709u }, { 17189487779326395846u, 2145249268790815535u },
{ 13751590223461116677u, 1716199415032652428u }, { 18379969808252713988u, 1372959532026121942u },
{ 14650556434236701088u, 2196735251241795108u }, { 652398703163629901u, 1757388200993436087u },
{ 11589965406756634890u, 1405910560794748869u }, { 7475898206584884855u, 2249456897271598191u },
{ 2291369750525997561u, 1799565517817278553u }, { 9211793429904618695u, 1439652414253822842u },
{ 18428218302589300235u, 2303443862806116547u }, { 7363877012587619542u, 1842755090244893238u },
{ 13269799239553916280u, 1474204072195914590u }, { 10615839391643133024u, 1179363257756731672u },
{ 2227947767661371545u, 1886981212410770676u }, { 16539753473096738529u, 1509584969928616540u },
{ 13231802778477390823u, 1207667975942893232u }, { 6413489186596184024u, 1932268761508629172u },
{ 16198837793502678189u, 1545815009206903337u }, { 5580372605318321905u, 1236652007365522670u },
{ 8928596168509315048u, 1978643211784836272u }, { 18210923379033183008u, 1582914569427869017u },
{ 7190041073742725760u, 1266331655542295214u }, { 436019273762630246u, 2026130648867672343u },
{ 7727513048493924843u, 1620904519094137874u }, { 9871359253537050198u, 1296723615275310299u },
{ 4726128361433549347u, 2074757784440496479u }, { 7470251503888749801u, 1659806227552397183u },
{ 13354898832594820487u, 1327844982041917746u }, { 13989140502667892133u, 2124551971267068394u },
{ 14880661216876224029u, 1699641577013654715u }, { 11904528973500979224u, 1359713261610923772u },
{ 4289851098633925465u, 2175541218577478036u }, { 18189276137874781665u, 1740432974861982428u },
{ 3483374466074094362u, 1392346379889585943u }, { 1884050330976640656u, 2227754207823337509u },
{ 5196589079523222848u, 1782203366258670007u }, { 15225317707844309248u, 1425762693006936005u },
{ 5913764258841343181u, 2281220308811097609u }, { 8420360221814984868u, 1824976247048878087u },
{ 17804334621677718864u, 1459980997639102469u }, { 17932816512084085415u, 1167984798111281975u },
{ 10245762345624985047u, 1868775676978051161u }, { 4507261061758077715u, 1495020541582440929u },
{ 7295157664148372495u, 1196016433265952743u }, { 7982903447895485668u, 1913626293225524389u },
{ 10075671573058298858u, 1530901034580419511u }, { 4371188443704728763u, 1224720827664335609u },
{ 14372599139411386667u, 1959553324262936974u }, { 15187428126271019657u, 1567642659410349579u },
{ 15839291315758726049u, 1254114127528279663u }, { 3206773216762499739u, 2006582604045247462u },
{ 13633465017635730761u, 1605266083236197969u }, { 14596120828850494932u, 1284212866588958375u },
{ 4907049252451240275u, 2054740586542333401u }, { 236290587219081897u, 1643792469233866721u },
{ 14946427728742906810u, 1315033975387093376u }, { 16535586736504830250u, 2104054360619349402u },
{ 5849771759720043554u, 1683243488495479522u }, { 15747863852001765813u, 1346594790796383617u },
{ 10439186904235184007u, 2154551665274213788u }, { 15730047152871967852u, 1723641332219371030u },
{ 12584037722297574282u, 1378913065775496824u }, { 9066413911450387881u, 2206260905240794919u },
{ 10942479943902220628u, 1765008724192635935u }, { 8753983955121776503u, 1412006979354108748u },
{ 10317025513452932081u, 2259211166966573997u }, { 874922781278525018u, 1807368933573259198u },
{ 8078635854506640661u, 1445895146858607358u }, { 13841606313089133175u, 1156716117486885886u },
{ 14767872471458792434u, 1850745787979017418u }, { 746251532941302978u, 1480596630383213935u },
{ 597001226353042382u, 1184477304306571148u }, { 15712597221132509104u, 1895163686890513836u },
{ 8880728962164096960u, 1516130949512411069u }, { 10793931984473187891u, 1212904759609928855u },
{ 17270291175157100626u, 1940647615375886168u }, { 2748186495899949531u, 1552518092300708935u },
{ 2198549196719959625u, 1242014473840567148u }, { 18275073973719576693u, 1987223158144907436u },
{ 10930710364233751031u, 1589778526515925949u }, { 12433917106128911148u, 1271822821212740759u },
{ 8826220925580526867u, 2034916513940385215u }, { 7060976740464421494u, 1627933211152308172u },
{ 16716827836597268165u, 1302346568921846537u }, { 11989529279587987770u, 2083754510274954460u },
{ 9591623423670390216u, 1667003608219963568u }, { 15051996368420132820u, 1333602886575970854u },
{ 13015147745246481542u, 2133764618521553367u }, { 3033420566713364587u, 1707011694817242694u },
{ 6116085268112601993u, 1365609355853794155u }, { 9785736428980163188u, 2184974969366070648u },
{ 15207286772667951197u, 1747979975492856518u }, { 1097782973908629988u, 1398383980394285215u },
{ 1756452758253807981u, 2237414368630856344u }, { 5094511021344956708u, 1789931494904685075u },
{ 4075608817075965366u, 1431945195923748060u }, { 6520974107321544586u, 2291112313477996896u },
{ 1527430471115325346u, 1832889850782397517u }, { 12289990821117991246u, 1466311880625918013u },
{ 17210690286378213644u, 1173049504500734410u }, { 9090360384495590213u, 1876879207201175057u },
{ 18340334751822203140u, 1501503365760940045u }, { 14672267801457762512u, 1201202692608752036u },
{ 16096930852848599373u, 1921924308174003258u }, { 1809498238053148529u, 1537539446539202607u },
{ 12515645034668249793u, 1230031557231362085u }, { 1578287981759648052u, 1968050491570179337u },
{ 12330676829633449412u, 1574440393256143469u }, { 13553890278448669853u, 1259552314604914775u },
{ 3239480371808320148u, 2015283703367863641u }, { 17348979556414297411u, 1612226962694290912u },
{ 6500486015647617283u, 1289781570155432730u }, { 10400777625036187652u, 2063650512248692368u },
{ 15699319729512770768u, 1650920409798953894u }, { 16248804598352126938u, 1320736327839163115u },
{ 7551343283653851484u, 2113178124542660985u }, { 6041074626923081187u, 1690542499634128788u },
{ 12211557331022285596u, 1352433999707303030u }, { 1091747655926105338u, 2163894399531684849u },
{ 4562746939482794594u, 1731115519625347879u }, { 7339546366328145998u, 1384892415700278303u },
{ 8053925371383123274u, 2215827865120445285u }, { 6443140297106498619u, 1772662292096356228u },
{ 12533209867169019542u, 1418129833677084982u }, { 5295740528502789974u, 2269007733883335972u },
{ 15304638867027962949u, 1815206187106668777u }, { 4865013464138549713u, 1452164949685335022u },
{ 14960057215536570740u, 1161731959748268017u }, { 9178696285890871890u, 1858771135597228828u },
{ 14721654658196518159u, 1487016908477783062u }, { 4398626097073393881u, 1189613526782226450u },
{ 7037801755317430209u, 1903381642851562320u }, { 5630241404253944167u, 1522705314281249856u },
{ 814844308661245011u, 1218164251424999885u }, { 1303750893857992017u, 1949062802279999816u },
{ 15800395974054034906u, 1559250241823999852u }, { 5261619149759407279u, 1247400193459199882u },
{ 12107939454356961969u, 1995840309534719811u }, { 5997002748743659252u, 1596672247627775849u },
{ 8486951013736837725u, 1277337798102220679u }, { 2511075177753209390u, 2043740476963553087u },
{ 13076906586428298482u, 1634992381570842469u }, { 14150874083884549109u, 1307993905256673975u },
{ 4194654460505726958u, 2092790248410678361u }, { 18113118827372222859u, 1674232198728542688u },
{ 3422448617672047318u, 1339385758982834151u }, { 16543964232501006678u, 2143017214372534641u },
{ 9545822571258895019u, 1714413771498027713u }, { 15015355686490936662u, 1371531017198422170u },
{ 5577825024675947042u, 2194449627517475473u }, { 11840957649224578280u, 1755559702013980378u },
{ 16851463748863483271u, 1404447761611184302u }, { 12204946739213931940u, 2247116418577894884u },
{ 13453306206113055875u, 1797693134862315907u }, { 3383947335406624054u, 1438154507889852726u },
{ 16482362180876329456u, 2301047212623764361u }, { 9496540929959153242u, 1840837770099011489u },
{ 11286581558709232917u, 1472670216079209191u }, { 5339916432225476010u, 1178136172863367353u },
{ 4854517476818851293u, 1885017876581387765u }, { 3883613981455081034u, 1508014301265110212u },
{ 14174937629389795797u, 1206411441012088169u }, { 11611853762797942306u, 1930258305619341071u },
{ 5600134195496443521u, 1544206644495472857u }, { 15548153800622885787u, 1235365315596378285u },
{ 6430302007287065643u, 1976584504954205257u }, { 16212288050055383484u, 1581267603963364205u },
{ 12969830440044306787u, 1265014083170691364u }, { 9683682259845159889u, 2024022533073106183u },
{ 15125643437359948558u, 1619218026458484946u }, { 8411165935146048523u, 1295374421166787957u },
{ 17147214310975587960u, 2072599073866860731u }, { 10028422634038560045u, 1658079259093488585u },
{ 8022738107230848036u, 1326463407274790868u }, { 9147032156827446534u, 2122341451639665389u },
{ 11006974540203867551u, 1697873161311732311u }, { 5116230817421183718u, 1358298529049385849u },
{ 15564666937357714594u, 2173277646479017358u }, { 1383687105660440706u, 1738622117183213887u },
{ 12174996128754083534u, 1390897693746571109u }, { 8411947361780802685u, 2225436309994513775u },
{ 6729557889424642148u, 1780349047995611020u }, { 5383646311539713719u, 1424279238396488816u },
{ 1235136468979721303u, 2278846781434382106u }, { 15745504434151418335u, 1823077425147505684u },
{ 16285752362063044992u, 1458461940118004547u }, { 5649904260166615347u, 1166769552094403638u },
{ 5350498001524674232u, 1866831283351045821u }, { 591049586477829062u, 1493465026680836657u },
{ 11540886113407994219u, 1194772021344669325u }, { 18673707743239135u, 1911635234151470921u },
{ 14772334225162232601u, 1529308187321176736u }, { 8128518565387875758u, 1223446549856941389u },
{ 1937583260394870242u, 1957514479771106223u }, { 8928764237799716840u, 1566011583816884978u },
{ 14521709019723594119u, 1252809267053507982u }, { 8477339172590109297u, 2004494827285612772u },
{ 17849917782297818407u, 1603595861828490217u }, { 6901236596354434079u, 1282876689462792174u },
{ 18420676183650915173u, 2052602703140467478u }, { 3668494502695001169u, 1642082162512373983u },
{ 10313493231639821582u, 1313665730009899186u }, { 9122891541139893884u, 2101865168015838698u },
{ 14677010862395735754u, 1681492134412670958u }, { 673562245690857633u, 1345193707530136767u }
};
static const uint64_t DOUBLE_POW5_SPLIT[DOUBLE_POW5_TABLE_SIZE][2] = {
{ 0u, 1152921504606846976u }, { 0u, 1441151880758558720u },
{ 0u, 1801439850948198400u }, { 0u, 2251799813685248000u },
{ 0u, 1407374883553280000u }, { 0u, 1759218604441600000u },
{ 0u, 2199023255552000000u }, { 0u, 1374389534720000000u },
{ 0u, 1717986918400000000u }, { 0u, 2147483648000000000u },
{ 0u, 1342177280000000000u }, { 0u, 1677721600000000000u },
{ 0u, 2097152000000000000u }, { 0u, 1310720000000000000u },
{ 0u, 1638400000000000000u }, { 0u, 2048000000000000000u },
{ 0u, 1280000000000000000u }, { 0u, 1600000000000000000u },
{ 0u, 2000000000000000000u }, { 0u, 1250000000000000000u },
{ 0u, 1562500000000000000u }, { 0u, 1953125000000000000u },
{ 0u, 1220703125000000000u }, { 0u, 1525878906250000000u },
{ 0u, 1907348632812500000u }, { 0u, 1192092895507812500u },
{ 0u, 1490116119384765625u }, { 4611686018427387904u, 1862645149230957031u },
{ 9799832789158199296u, 1164153218269348144u }, { 12249790986447749120u, 1455191522836685180u },
{ 15312238733059686400u, 1818989403545856475u }, { 14528612397897220096u, 2273736754432320594u },
{ 13692068767113150464u, 1421085471520200371u }, { 12503399940464050176u, 1776356839400250464u },
{ 15629249925580062720u, 2220446049250313080u }, { 9768281203487539200u, 1387778780781445675u },
{ 7598665485932036096u, 1734723475976807094u }, { 274959820560269312u, 2168404344971008868u },
{ 9395221924704944128u, 1355252715606880542u }, { 2520655369026404352u, 1694065894508600678u },
{ 12374191248137781248u, 2117582368135750847u }, { 14651398557727195136u, 1323488980084844279u },
{ 13702562178731606016u, 1654361225106055349u }, { 3293144668132343808u, 2067951531382569187u },
{ 18199116482078572544u, 1292469707114105741u }, { 8913837547316051968u, 1615587133892632177u },
{ 15753982952572452864u, 2019483917365790221u }, { 12152082354571476992u, 1262177448353618888u },
{ 15190102943214346240u, 1577721810442023610u }, { 9764256642163156992u, 1972152263052529513u },
{ 17631875447420442880u, 1232595164407830945u }, { 8204786253993389888u, 1540743955509788682u },
{ 1032610780636961552u, 1925929944387235853u }, { 2951224747111794922u, 1203706215242022408u },
{ 3689030933889743652u, 1504632769052528010u }, { 13834660704216955373u, 1880790961315660012u },
{ 17870034976990372916u, 1175494350822287507u }, { 17725857702810578241u, 1469367938527859384u },
{ 3710578054803671186u, 1836709923159824231u }, { 26536550077201078u, 2295887403949780289u },
{ 11545800389866720434u, 1434929627468612680u }, { 14432250487333400542u, 1793662034335765850u },
{ 8816941072311974870u, 2242077542919707313u }, { 17039803216263454053u, 1401298464324817070u },
{ 12076381983474541759u, 1751623080406021338u }, { 5872105442488401391u, 2189528850507526673u },
{ 15199280947623720629u, 1368455531567204170u }, { 9775729147674874978u, 1710569414459005213u },
{ 16831347453020981627u, 2138211768073756516u }, { 1296220121283337709u, 1336382355046097823u },
{ 15455333206886335848u, 1670477943807622278u }, { 10095794471753144002u, 2088097429759527848u },
{ 6309871544845715001u, 1305060893599704905u }, { 12499025449484531656u, 1631326116999631131u },
{ 11012095793428276666u, 2039157646249538914u }, { 11494245889320060820u, 1274473528905961821u },
{ 532749306367912313u, 1593091911132452277u }, { 5277622651387278295u, 1991364888915565346u },
{ 7910200175544436838u, 1244603055572228341u }, { 14499436237857933952u, 1555753819465285426u },
{ 8900923260467641632u, 1944692274331606783u }, { 12480606065433357876u, 1215432671457254239u },
{ 10989071563364309441u, 1519290839321567799u }, { 9124653435777998898u, 1899113549151959749u },
{ 8008751406574943263u, 1186945968219974843u }, { 5399253239791291175u, 1483682460274968554u },
{ 15972438586593889776u, 1854603075343710692u }, { 759402079766405302u, 1159126922089819183u },
{ 14784310654990170340u, 1448908652612273978u }, { 9257016281882937117u, 1811135815765342473u },
{ 16182956370781059300u, 2263919769706678091u }, { 7808504722524468110u, 1414949856066673807u },
{ 5148944884728197234u, 1768687320083342259u }, { 1824495087482858639u, 2210859150104177824u },
{ 1140309429676786649u, 1381786968815111140u }, { 1425386787095983311u, 1727233711018888925u },
{ 6393419502297367043u, 2159042138773611156u }, { 13219259225790630210u, 1349401336733506972u },
{ 16524074032238287762u, 1686751670916883715u }, { 16043406521870471799u, 2108439588646104644u },
{ 803757039314269066u, 1317774742903815403u }, { 14839754354425000045u, 1647218428629769253u },
{ 4714634887749086344u, 2059023035787211567u }, { 9864175832484260821u, 1286889397367007229u },
{ 16941905809032713930u, 1608611746708759036u }, { 2730638187581340797u, 2010764683385948796u },
{ 10930020904093113806u, 1256727927116217997u }, { 18274212148543780162u, 1570909908895272496u },
{ 4396021111970173586u, 1963637386119090621u }, { 5053356204195052443u, 1227273366324431638u },
{ 15540067292098591362u, 1534091707905539547u }, { 14813398096695851299u, 1917614634881924434u },
{ 13870059828862294966u, 1198509146801202771u }, { 12725888767650480803u, 1498136433501503464u },
{ 15907360959563101004u, 1872670541876879330u }, { 14553786618154326031u, 1170419088673049581u },
{ 4357175217410743827u, 1463023860841311977u }, { 10058155040190817688u, 1828779826051639971u },
{ 7961007781811134206u, 2285974782564549964u }, { 14199001900486734687u, 1428734239102843727u },
{ 13137066357181030455u, 1785917798878554659u }, { 11809646928048900164u, 2232397248598193324u },
{ 16604401366885338411u, 1395248280373870827u }, { 16143815690179285109u, 1744060350467338534u },
{ 10956397575869330579u, 2180075438084173168u }, { 6847748484918331612u, 1362547148802608230u },
{ 17783057643002690323u, 1703183936003260287u }, { 17617136035325974999u, 2128979920004075359u },
{ 17928239049719816230u, 1330612450002547099u }, { 17798612793722382384u, 1663265562503183874u },
{ 13024893955298202172u, 2079081953128979843u }, { 5834715712847682405u, 1299426220705612402u },
{ 16516766677914378815u, 1624282775882015502u }, { 11422586310538197711u, 2030353469852519378u },
{ 11750802462513761473u, 1268970918657824611u }, { 10076817059714813937u, 1586213648322280764u },
{ 12596021324643517422u, 1982767060402850955u }, { 5566670318688504437u, 1239229412751781847u },
{ 2346651879933242642u, 1549036765939727309u }, { 7545000868343941206u, 1936295957424659136u },
{ 4715625542714963254u, 1210184973390411960u }, { 5894531928393704067u, 1512731216738014950u },
{ 16591536947346905892u, 1890914020922518687u }, { 17287239619732898039u, 1181821263076574179u },
{ 16997363506238734644u, 1477276578845717724u }, { 2799960309088866689u, 1846595723557147156u },
{ 10973347230035317489u, 1154122327223216972u }, { 13716684037544146861u, 1442652909029021215u },
{ 12534169028502795672u, 1803316136286276519u }, { 11056025267201106687u, 2254145170357845649u },
{ 18439230838069161439u, 1408840731473653530u }, { 13825666510731675991u, 1761050914342066913u },
{ 3447025083132431277u, 2201313642927583642u }, { 6766076695385157452u, 1375821026829739776u },
{ 8457595869231446815u, 1719776283537174720u }, { 10571994836539308519u, 2149720354421468400u },
{ 6607496772837067824u, 1343575221513417750u }, { 17482743002901110588u, 1679469026891772187u },
{ 17241742735199000331u, 2099336283614715234u }, { 15387775227926763111u, 1312085177259197021u },
{ 5399660979626290177u, 1640106471573996277u }, { 11361262242960250625u, 2050133089467495346u },
{ 11712474920277544544u, 1281333180917184591u }, { 10028907631919542777u, 1601666476146480739u },
{ 7924448521472040567u, 2002083095183100924u }, { 14176152362774801162u, 1251301934489438077u },
{ 3885132398186337741u, 1564127418111797597u }, { 9468101516160310080u, 1955159272639746996u },
{ 15140935484454969608u, 1221974545399841872u }, { 479425281859160394u, 1527468181749802341u },
{ 5210967620751338397u, 1909335227187252926u }, { 17091912818251750210u, 1193334516992033078u },
{ 12141518985959911954u, 1491668146240041348u }, { 15176898732449889943u, 1864585182800051685u },
{ 11791404716994875166u, 1165365739250032303u }, { 10127569877816206054u, 1456707174062540379u },
{ 8047776328842869663u, 1820883967578175474u }, { 836348374198811271u, 2276104959472719343u },
{ 7440246761515338900u, 1422565599670449589u }, { 13911994470321561530u, 1778206999588061986u },
{ 8166621051047176104u, 2222758749485077483u }, { 2798295147690791113u, 1389224218428173427u },
{ 17332926989895652603u, 1736530273035216783u }, { 17054472718942177850u, 2170662841294020979u },
{ 8353202440125167204u, 1356664275808763112u }, { 10441503050156459005u, 1695830344760953890u },
{ 3828506775840797949u, 2119787930951192363u }, { 86973725686804766u, 1324867456844495227u },
{ 13943775212390669669u, 1656084321055619033u }, { 3594660960206173375u, 2070105401319523792u },
{ 2246663100128858359u, 1293815875824702370u }, { 12031700912015848757u, 1617269844780877962u },
{ 5816254103165035138u, 2021587305976097453u }, { 5941001823691840913u, 1263492066235060908u },
{ 7426252279614801142u, 1579365082793826135u }, { 4671129331091113523u, 1974206353492282669u },
{ 5225298841145639904u, 1233878970932676668u }, { 6531623551432049880u, 1542348713665845835u },
{ 3552843420862674446u, 1927935892082307294u }, { 16055585193321335241u, 1204959932551442058u },
{ 10846109454796893243u, 1506199915689302573u }, { 18169322836923504458u, 1882749894611628216u },
{ 11355826773077190286u, 1176718684132267635u }, { 9583097447919099954u, 1470898355165334544u },
{ 11978871809898874942u, 1838622943956668180u }, { 14973589762373593678u, 2298278679945835225u },
{ 2440964573842414192u, 1436424174966147016u }, { 3051205717303017741u, 1795530218707683770u },
{ 13037379183483547984u, 2244412773384604712u }, { 8148361989677217490u, 1402757983365377945u },
{ 14797138505523909766u, 1753447479206722431u }, { 13884737113477499304u, 2191809349008403039u },
{ 15595489723564518921u, 1369880843130251899u }, { 14882676136028260747u, 1712351053912814874u },
{ 9379973133180550126u, 2140438817391018593u }, { 17391698254306313589u, 1337774260869386620u },
{ 3292878744173340370u, 1672217826086733276u }, { 4116098430216675462u, 2090272282608416595u },
{ 266718509671728212u, 1306420176630260372u }, { 333398137089660265u, 1633025220787825465u },
{ 5028433689789463235u, 2041281525984781831u }, { 10060300083759496378u, 1275800953740488644u },
{ 12575375104699370472u, 1594751192175610805u }, { 1884160825592049379u, 1993438990219513507u },
{ 17318501580490888525u, 1245899368887195941u }, { 7813068920331446945u, 1557374211108994927u },
{ 5154650131986920777u, 1946717763886243659u }, { 915813323278131534u, 1216698602428902287u },
{ 14979824709379828129u, 1520873253036127858u }, { 9501408849870009354u, 1901091566295159823u },
{ 12855909558809837702u, 1188182228934474889u }, { 2234828893230133415u, 1485227786168093612u },
{ 2793536116537666769u, 1856534732710117015u }, { 8663489100477123587u, 1160334207943823134u },
{ 1605989338741628675u, 1450417759929778918u }, { 11230858710281811652u, 1813022199912223647u },
{ 9426887369424876662u, 2266277749890279559u }, { 12809333633531629769u, 1416423593681424724u },
{ 16011667041914537212u, 1770529492101780905u }, { 6179525747111007803u, 2213161865127226132u },
{ 13085575628799155685u, 1383226165704516332u }, { 16356969535998944606u, 1729032707130645415u },
{ 15834525901571292854u, 2161290883913306769u }, { 2979049660840976177u, 1350806802445816731u },
{ 17558870131333383934u, 1688508503057270913u }, { 8113529608884566205u, 2110635628821588642u },
{ 9682642023980241782u, 1319147268013492901u }, { 16714988548402690132u, 1648934085016866126u },
{ 11670363648648586857u, 2061167606271082658u }, { 11905663298832754689u, 1288229753919426661u },
{ 1047021068258779650u, 1610287192399283327u }, { 15143834390605638274u, 2012858990499104158u },
{ 4853210475701136017u, 1258036869061940099u }, { 1454827076199032118u, 1572546086327425124u },
{ 1818533845248790147u, 1965682607909281405u }, { 3442426662494187794u, 1228551629943300878u },
{ 13526405364972510550u, 1535689537429126097u }, { 3072948650933474476u, 1919611921786407622u },
{ 15755650962115585259u, 1199757451116504763u }, { 15082877684217093670u, 1499696813895630954u },
{ 9630225068416591280u, 1874621017369538693u }, { 8324733676974063502u, 1171638135855961683u },
{ 5794231077790191473u, 1464547669819952104u }, { 7242788847237739342u, 1830684587274940130u },
{ 18276858095901949986u, 2288355734093675162u }, { 16034722328366106645u, 1430222333808546976u },
{ 1596658836748081690u, 1787777917260683721u }, { 6607509564362490017u, 2234722396575854651u },
{ 1823850468512862308u, 1396701497859909157u }, { 6891499104068465790u, 1745876872324886446u },
{ 17837745916940358045u, 2182346090406108057u }, { 4231062170446641922u, 1363966306503817536u },
{ 5288827713058302403u, 1704957883129771920u }, { 6611034641322878003u, 2131197353912214900u },
{ 13355268687681574560u, 1331998346195134312u }, { 16694085859601968200u, 1664997932743917890u },
{ 11644235287647684442u, 2081247415929897363u }, { 4971804045566108824u, 1300779634956185852u },
{ 6214755056957636030u, 1625974543695232315u }, { 3156757802769657134u, 2032468179619040394u },
{ 6584659645158423613u, 1270292612261900246u }, { 17454196593302805324u, 1587865765327375307u },
{ 17206059723201118751u, 1984832206659219134u }, { 6142101308573311315u, 1240520129162011959u },
{ 3065940617289251240u, 1550650161452514949u }, { 8444111790038951954u, 1938312701815643686u },
{ 665883850346957067u, 1211445438634777304u }, { 832354812933696334u, 1514306798293471630u },
{ 10263815553021896226u, 1892883497866839537u }, { 17944099766707154901u, 1183052186166774710u },
{ 13206752671529167818u, 1478815232708468388u }, { 16508440839411459773u, 1848519040885585485u },
{ 12623618533845856310u, 1155324400553490928u }, { 15779523167307320387u, 1444155500691863660u },
{ 1277659885424598868u, 1805194375864829576u }, { 1597074856780748586u, 2256492969831036970u },
{ 5609857803915355770u, 1410308106144398106u }, { 16235694291748970521u, 1762885132680497632u },
{ 1847873790976661535u, 2203606415850622041u }, { 12684136165428883219u, 1377254009906638775u },
{ 11243484188358716120u, 1721567512383298469u }, { 219297180166231438u, 2151959390479123087u },
{ 7054589765244976505u, 1344974619049451929u }, { 13429923224983608535u, 1681218273811814911u },
{ 12175718012802122765u, 2101522842264768639u }, { 14527352785642408584u, 1313451776415480399u },
{ 13547504963625622826u, 1641814720519350499u }, { 12322695186104640628u, 2052268400649188124u },
{ 16925056528170176201u, 1282667750405742577u }, { 7321262604930556539u, 1603334688007178222u },
{ 18374950293017971482u, 2004168360008972777u }, { 4566814905495150320u, 1252605225005607986u },
{ 14931890668723713708u, 1565756531257009982u }, { 9441491299049866327u, 1957195664071262478u },
{ 1289246043478778550u, 1223247290044539049u }, { 6223243572775861092u, 1529059112555673811u },
{ 3167368447542438461u, 1911323890694592264u }, { 1979605279714024038u, 1194577431684120165u },
{ 7086192618069917952u, 1493221789605150206u }, { 18081112809442173248u, 1866527237006437757u },
{ 13606538515115052232u, 1166579523129023598u }, { 7784801107039039482u, 1458224403911279498u },
{ 507629346944023544u, 1822780504889099373u }, { 5246222702107417334u, 2278475631111374216u },
{ 3278889188817135834u, 1424047269444608885u }, { 8710297504448807696u, 1780059086805761106u }
};
#endif // RYU_D2S_FULL_TABLE_H

View File

@ -1,48 +0,0 @@
static inline bool isbase(int c, int base) {
int val = 0;
if(isdigit(c)) {
val = c-'0';
}
else if(islower(c)) {
val = c-'a'+10;
}
else if(isupper(c)) {
val = c-'A'+10;
}
else {
return false;
}
return val < base;
}
static inline intl todigit(int c) {
int val = 0;
if(isdigit(c)) {
val = c-'0';
}
else if(islower(c)) {
val = c-'a'+10;
}
else if(isupper(c)) {
val = c-'A'+10;
}
return val;
}
static inline int fromdigit(int digit, int upper) {
int ch;
if(digit < 10) {
ch = digit+'0';
}
else {
if(upper) {
ch = digit-10+'A';
}
else {
ch = digit-10+'a';
}
}
return ch;
}

View File

@ -1,130 +0,0 @@
static f64 strtod_generic(const char *restrict nptr, char **restrict endptr) {
const char *restrict str = nptr;
bool conv_performed = false;
f64 value = 0.0;
f64 coef = 1.0;
// Skip space on the beginning
while(isspace(*str)) {
++str;
}
// Check for inf and nan
if(strpfx_i(str, "INF")) {
str += sizeof "INF"-1;
value = HUGE_VAL;
conv_performed = true;
goto finish;
}
if(strpfx_i(str, "INFINITY")) {
str += sizeof "INFINITY"-1;
value = HUGE_VAL;
conv_performed = true;
goto finish;
}
if(strpfx_i(str, "NAN")) {
str += sizeof "NAN"-1;
value = NAN;
conv_performed = true;
if(*str == '(') {
while(*str != ')') {
++str;
}
++str;
}
goto finish;
}
// Parse C float
if(*str == '+') {
++str;
}
else if(*str == '-') {
coef = -1.;
++str;
}
int base = 10;
if(strpfx_i(str, "0X")) {
str += sizeof "0X"-1;
base = 16;
}
// Parse the whole part
while(isbase(*str, base)) {
long digit = todigit(*str);
value = 10.0*value + (f64)digit;
++str;
}
if(*str != '.') {
value = 0.0;
goto finish;
}
++str;
// Parse the fractional part
long exp = 1;
while(isbase(*str, base)) {
long digit = todigit(*str);
f64 fract = (f64)digit;
long cexp = exp;
while(cexp-- != 0) {
fract /= (f64)base;
}
value += fract;
++exp;
++str;
}
// Parse the exponent
if((base == 10 && strpfx_i(str, "E"))
|| (base == 16 && strpfx_i(str, "P")))
{
++str;
long exp = 0;
long exp_coef = 1;
if(*str == '+') {
++str;
}
else if(*str == '-') {
exp_coef = -1;
++str;
}
while(isdigit(*str)) {
exp = 10*exp + (long)(*str-'0');
++str;
}
if(exp_coef == 1) {
while(exp--!=0) value = value * base;
}
else if(exp_coef == -1) {
while(exp--!=0) value = value / base;
}
}
if(!isfinite(value)) {
errno = ERANGE;
value = coef*HUGE_VAL;
}
conv_performed = true;
finish:
if(endptr != NULL) {
if(conv_performed) {
*endptr = (char *)str;
}
else {
*endptr = (char *)nptr;
}
}
return coef*value;
}
f64 strtod(const char *restrict nptr, char **restrict endptr) {
return strtod_generic(nptr, endptr);
}
f32 strtof(const char *restrict nptr, char **restrict endptr) {
return (f32)strtod_generic(nptr, endptr);
}
fl64 strtold(const char *restrict nptr, char **restrict endptr) {
return (fl64)strtod_generic(nptr, endptr);
}
f64 atof(const char *nptr) {
return strtod(nptr, (char **)NULL);
}

View File

@ -1,169 +0,0 @@
static intull strtoi_generic(const char *restrict nptr,
char **restrict endptr,
int inbase,
intl *coefptr,
intull int_max) {
const char *restrict str = nptr;
intull value = 0;
int digits_read = 0;
bool is_signed = (coefptr != NULL);
intl coef = 1;
// Find max{abs(int)}. Signed integers have negative,
// whose absolute value is 1 bigger than int_max.
intull int_abs_max = int_max;
if(is_signed) {
++int_abs_max;
}
if(!IN_RANGE(0, inbase, 36)) {
goto finish;
}
intull base = (intull)inbase;
// Skip space on the beginning
while(isspace(*str)) {
++str;
}
// Parse sign
if(is_signed) {
if(*str == '-') {
coef = -1;
++str;
}
}
if(*str == '+') {
++str;
}
// See if we need to parse base in C-like format
// then set the base accordingly
if(strpfx_i(str, "0X")) {
++str;
if(base == 16 || base == 0) {
++str;
base = 16;
}
else {
goto finish;
}
}
else if(*str == '0') {
++str;
++digits_read;
if(base == 8 || base == 0) {
base = 8;
}
}
// Parse the string of digits in the given base. If the value
// exceeds abs(int_min) we exit with range error.
while(isbase(*str, (int)base)) {
intull digit = (intull)todigit(*str);
if(value > (int_abs_max - digit)/base) {
goto error_out_of_range;
}
value = base*value + digit;
++str;
++digits_read;
}
// We only allow the modulo of value equal to abs(int_min) if it is
// preceeded by the minus sign.
if(is_signed) {
if(value == int_abs_max && coef != -1) {
goto error_out_of_range;
}
}
goto finish;
error_out_of_range:
// Skip the remainder of the subject string
while(isbase(*str, (int)base)) {
++str;
}
errno = ERANGE;
value = int_max;
goto finish;
finish:;
// If no conversion is performed we return the value of 0 and *endptr
// is set to the nptr.
bool conv_performed = (digits_read > 0);
if(!conv_performed) {
value = 0;
}
if(endptr != NULL) {
if(!conv_performed) {
*endptr = (char *)nptr;
}
else {
*endptr = (char *)str;
}
}
*coefptr = coef;
return value;
}
intl strtol(const char *restrict nptr, char **restrict endptr, int base) {
intull int_max = (intull)LONG_MAX;
intl coef;
intull modulo = strtoi_generic(nptr, endptr, base, &coef, int_max);
intl value;
if(modulo == int_max) {
value = LONG_MIN;
}
else {
value = coef * (intl)modulo;
}
return value;
}
intll strtoll(const char *restrict nptr, char **restrict endptr, int base) {
intull int_max = (intull)LLONG_MAX;
intl coef;
intull modulo = strtoi_generic(nptr, endptr, base, &coef, int_max);
intll value;
if(modulo == int_max) {
value = LLONG_MIN;
}
else {
value = (intll)coef * (intll)modulo;
}
return value;
}
intul strtoul(const char *restrict nptr, char **restrict endptr, int base) {
intull int_max = (intull)ULONG_MAX;
intull value = strtoi_generic(nptr, endptr, base, NULL, int_max);
return (intul)value;
}
intull strtoull(const char *restrict nptr, char **restrict endptr, int base) {
intull int_max = (intull)ULLONG_MAX;
return strtoi_generic(nptr, endptr, base, NULL, int_max);
}
int atoi(const char *nptr) {
return (int)strtol(nptr, (char **)NULL, 10);
}
long int atol(const char *nptr) {
return strtol(nptr, (char **)NULL, 10);
}
long long int atoll(const char *nptr) {
return strtoll(nptr, (char **)NULL, 10);
}
char *itoa(int value, char *str, int base) {
int sign = 0;
if(value < 0) {
sign = 1;
value = -value;
}
char buf[20] = {0};
char *bufp = buf + sizeof buf - 1;
do {
*--bufp = value%base+'0';
value /= base;
} while(value != 0);
if(sign) {
*--bufp = '-';
}
strcpy(str, bufp);
return str;
}

View File

@ -1,10 +0,0 @@
static bool strpfx_i(char const *restrict str, char const *restrict prefix) {
while(*prefix != 0) {
if(*str == 0) break;
if(toupper(*str) != toupper(*prefix)) return false;
++prefix;
++str;
}
return true;
}

View File

@ -1,67 +0,0 @@
int isalnum(int c) {
return isalpha(c) || isdigit(c);
}
int isalpha(int c) {
return islower(c) || isupper(c);
}
int isblank(int c) {
return c == ' ' || c == '\t';
}
int iscntrl(int c) {
return IN_RANGE('\x00', c, '\x1f') || c == '\x7f';
}
int isdigit(int c) {
return IN_RANGE('0', c, '9');
}
int isgraph(int c) {
return isprint(c) && (c != ' ');
}
int islower(int c) {
return IN_RANGE('a', c, 'z');
}
int isprint(int c) {
return IN_RANGE(' ', c, '\x7e');
}
int ispunct(int c) {
return IN_RANGE('\x21', c, '\x2f')
|| IN_RANGE('\x3a', c, '\x40')
|| IN_RANGE('\x5b', c, '\x60')
|| IN_RANGE('\x7b', c, '\x7e');
}
int isspace(int c) {
return IN_RANGE('\x09', c, '\x0d') || c == ' ';
}
int isupper(int c) {
return IN_RANGE('A', c, 'Z');
}
int isxdigit(int c) {
return IN_RANGE('0', c, '9')
|| IN_RANGE('a', c, 'f')
|| IN_RANGE('A', c, 'F');
}
int tolower(int c) {
if(isupper(c)) {
return c-'A'+'a';
}
return c;
}
int toupper(int c) {
if(islower(c)) {
return c-'a'+'A';
}
return c;
}

View File

@ -1,2 +0,0 @@
_Thread_local int errno;

View File

@ -1,121 +0,0 @@
#define fe_masks(excepts) (((fexcept_t)(excepts)) << 7)
#define fe_flags(excepts) ((fexcept_t)(excepts))
#define fe_excepts(masks) ((int)(masks >> 7))
fenv_t _fe_dfl_env = 0x1f80;
int feclearexcept(int excepts) {
if((excepts & FE_ALL_EXCEPT) != excepts) {
return 1;
}
if(excepts == 0) {
return 0;
}
fexcept_t csr = _mm_getcsr();
csr &= ~fe_flags(excepts);
_mm_setcsr(csr);
return 0;
}
int fegetexceptflag(fexcept_t *flagp, int excepts) {
if((excepts & FE_ALL_EXCEPT) != excepts) {
return 1;
}
*flagp = fe_flags(excepts);
return 0;
}
int feraiseexcept(int excepts) {
if((excepts & FE_ALL_EXCEPT) != excepts) {
return 1;
}
if(excepts == 0) {
return 0;
}
fexcept_t csr = _mm_getcsr();
csr |= fe_flags(excepts);
_mm_setcsr(csr);
return 0;
}
int fesetexceptflag(const fexcept_t *flagp, int excepts) {
if((excepts & FE_ALL_EXCEPT) != excepts) {
return 1;
}
if(excepts == 0) {
return 0;
}
fexcept_t flags = *flagp;
fexcept_t csr = _mm_getcsr();
csr |= flags;
_mm_setcsr(csr);
return 0;
}
int fetestexcept(int excepts) {
fexcept_t csr = _mm_getcsr();
fexcept_t flags = fe_flags(excepts);
return (int)(csr & flags);
}
int fegetround(void) {
fexcept_t csr = _mm_getcsr();
int round = (csr >> 13) & 0x3;
return round;
}
int fesetround(int round) {
if(!(0 <= round && round < 4)) {
return 1;
}
fexcept_t csr = _mm_getcsr();
csr &= ~(0x3 << 13);
csr |= round << 13;
_mm_setcsr(csr);
return 0;
}
int fegetenv(fenv_t *env) {
fenv_t csr = _mm_getcsr();
*env = csr;
return 0;
}
int fesetenv(fenv_t *env) {
_mm_setcsr(*env);
return 1;
}
int feholdexcept(fenv_t *envp) {
fegetenv(envp);
feclearexcept(FE_ALL_EXCEPT);
return 0;
}
int feupdateenv(fenv_t const *envp) {
int excepts = _mm_getcsr() & FE_ALL_EXCEPT;
_mm_setcsr(*envp);
feraiseexcept(excepts);
return 0;
}
int _feenabletraps(int excepts) {
if((excepts & FE_ALL_EXCEPT) != excepts) {
return 1;
}
fexcept_t csr = _mm_getcsr();
csr &= ~fe_masks(excepts);
_mm_setcsr(csr);
return 0;
}
int _fedisabletraps(int excepts) {
if((excepts & FE_ALL_EXCEPT) != excepts) {
return 1;
}
fexcept_t csr = _mm_getcsr();
csr |= fe_masks(excepts);
_mm_setcsr(csr);
return 0;
}

32
src/linux/crt_ctors.c Normal file
View File

@ -0,0 +1,32 @@
#include <cia_definitions.h>
// NOTE: These symbols are provided by the linker
#define attribute_hidden __attribute__((__visibility__("hidden")))
extern void (*__preinit_array_start []) (int, char **, char **) attribute_hidden;
extern void (*__preinit_array_end []) (int, char **, char **) attribute_hidden;
extern void (*__init_array_start []) (int, char **, char **) attribute_hidden;
extern void (*__init_array_end []) (int, char **, char **) attribute_hidden;
extern void (*__fini_array_start []) (void) attribute_hidden;
extern void (*__fini_array_end []) (void) attribute_hidden;
// extern void _init();
// extern void _fini();
// These will be called by __libc_start_main
void __libc_global_init(int argc, char **argv, char **envp) {
// _init();
u64 size = (u64)__init_array_end - (u64)__init_array_start;
for(u64 i = 0; i != size; ++i) {
(*__init_array_start[i])(argc, argv, envp);
}
}
void __libc_global_fini(int argc, char **argv, char **envp) {
u64 size = (u64)__fini_array_end - (u64)__fini_array_start;
u64 i = size;
while(i-- > 0) {
(*__fini_array_start[i])();
}
// _fini();
}

39
src/linux/crt_entry.asm Normal file
View File

@ -0,0 +1,39 @@
bits 64
section .text
global _start
; global _init
; global _fini
extern __libc_global_fini
extern __libc_global_init
extern __libc_start_main
extern main
; _init:
; push ebp
; mov ebp, esp
; _fini:
_start:
xor ebp, ebp
;; Save rtld_fini address to r9
mov r9, rdx
;; Get argc and argv from the stack
pop rsi
mov rdx, qword [rsp]
;; Align stack to 16, push junk and stack ptr
and rsi, ~0xf
push rax
push rsp
;; Push fini and init sections
mov rcx, __libc_global_init wrt ..got
mov r8, __libc_global_fini wrt ..got
mov rdi, main
;; Call start main
call __libc_start_main wrt ..plt
;; No idea why halt it, I guess that's a funny
;; way to crash your application if the function we called
;; returns instead of calling the exit syscall
hlt

11
src/linux/entry.c Normal file
View File

@ -0,0 +1,11 @@
void __libc_start_main(
int (*main)(int, char**, char**),
int argc, char **argv,
int (*init)(int, char**, char**),
void (*fini)(void),
void (*rtld_fini)(void),
void *stack_end
) {
syscall_exit(0);
}

137
src/linux/syscall.c Normal file
View File

@ -0,0 +1,137 @@
#if os_is_linux()
#define SYS_read 0
#define SYS_write 1
#define SYS_open 2
#define SYS_close 3
#define SYS_stat 4
#define SYS_fstat 5
#define SYS_lstat 6
#define SYS_poll 7
#define SYS_lseek 8
#define SYS_mmap 9
#define SYS_mprotect 10
#define SYS_munmap 11
#define SYS_brk 12
#define SYS_rt_sigaction 13
#define SYS_rt_sigprocmask 14
#define SYS_rt_sigreturn 15
#define SYS_ioctl 16
#define SYS_pread64 17
#define SYS_pwrite64 18
#define SYS_readv 19
#define SYS_writev 20
#define SYS_access 21
#define SYS_pipe 22
#define SYS_select 23
#define SYS_sched_yield 24
#define SYS_mremap 25
#define SYS_msync 26
#define SYS_mincore 27
#define SYS_madvise 28
#define SYS_shmget 29
#define SYS_shmat 30
#define SYS_shmctl 31
#define SYS_dup 32
#define SYS_dup2 33
#define SYS_pause 34
#define SYS_nanosleep 35
#define SYS_getitimer 36
#define SYS_alarm 37
#define SYS_setitimer 38
#define SYS_getpid 39
#define SYS_sendfile 40
#define SYS_socket 41
#define SYS_connect 42
#define SYS_accept 43
#define SYS_sendto 44
#define SYS_recvfrom 45
#define SYS_sendmsg 46
#define SYS_recvmsg 47
#define SYS_shutdown 48
#define SYS_bind 49
#define SYS_listen 50
#define SYS_getsockname 51
#define SYS_getpeername 52
#define SYS_socketpair 53
#define SYS_setsockopt 54
#define SYS_getsockopt 55
#define SYS_clone 56
#define SYS_fork 57
#define SYS_vfork 58
#define SYS_execve 59
#define SYS_exit 60
// Syscall stubs
static __inline i64 __syscall0(i64 n) {
i64 ret;
__asm__ __volatile__ ("syscall" : "=a"(ret) : "a"(n) : "rcx", "r11", "memory");
return ret;
}
static __inline i64 __syscall1(i64 n, i64 a1) {
i64 ret;
__asm__ __volatile__ ("syscall" : "=a"(ret) : "a"(n), "D"(a1) : "rcx", "r11", "memory");
return ret;
}
static __inline i64 __syscall2(i64 n, i64 a1, i64 a2) {
i64 ret;
__asm__ __volatile__ ("syscall" : "=a"(ret) : "a"(n), "D"(a1), "S"(a2)
: "rcx", "r11", "memory");
return ret;
}
static __inline i64 __syscall3(i64 n, i64 a1, i64 a2, i64 a3) {
i64 ret;
__asm__ __volatile__ ("syscall" : "=a"(ret) : "a"(n), "D"(a1), "S"(a2),
"d"(a3) : "rcx", "r11", "memory");
return ret;
}
static __inline i64 __syscall4(i64 n, i64 a1, i64 a2, i64 a3, i64 a4) {
i64 ret;
register i64 r10 __asm__("r10") = a4;
__asm__ __volatile__ ("syscall" : "=a"(ret) : "a"(n), "D"(a1), "S"(a2),
"d"(a3), "r"(r10): "rcx", "r11", "memory");
return ret;
}
static __inline i64 __syscall5(i64 n, i64 a1, i64 a2, i64 a3, i64 a4, i64 a5) {
i64 ret;
register i64 r10 __asm__("r10") = a4;
register i64 r8 __asm__("r8") = a5;
__asm__ __volatile__ ("syscall" : "=a"(ret) : "a"(n), "D"(a1), "S"(a2),
"d"(a3), "r"(r10), "r"(r8) : "rcx", "r11", "memory");
return ret;
}
static __inline i64 __syscall6(i64 n, i64 a1, i64 a2, i64 a3, i64 a4, i64 a5, i64 a6) {
i64 ret;
register i64 r10 __asm__("r10") = a4;
register i64 r8 __asm__("r8") = a5;
register i64 r9 __asm__("r9") = a6;
__asm__ __volatile__ ("syscall" : "=a"(ret) : "a"(n), "D"(a1), "S"(a2),
"d"(a3), "r"(r10), "r"(r8), "r"(r9) : "rcx", "r11", "memory");
return ret;
}
// Syscall wrappers
static inline i64 syscall_read(u32 fd, char *buf, u64 count) {
return __syscall3(SYS_read, (i64)fd, (i64)buf, (i64)count);
}
static inline i64 syscall_write(u32 fd, char const *buf, u64 count) {
return __syscall3(SYS_write, (i64)fd, (i64)buf, (u64)count);
}
static inline i64 syscall_exit(int code) {
return __syscall1(SYS_exit, (i64)code);
}
#else
#error "syscall.h should only be included in LINUX code"
#endif

View File

@ -1,61 +0,0 @@
#define _LC_FIRST 0
#define _LC_LAST 5
static struct lconv _locale;
static char _locale_str[16];
// Even if the user doesn't enable LIB_EXT1 we still have it existing
size_t strnlen_s(const char *s, size_t maxsize);
char *setlocale(int category, const char *locale) {
if (_LC_FIRST <= category && category <= _LC_LAST) return NULL;
if (locale == NULL) return _locale_str;
// Validate the string a bit
size_t locale_len = strnlen_s(locale, sizeof(_locale_str));
if (locale_len == 0 || locale_len >= sizeof(_locale_str)) return NULL;
if(strcmp(locale, "C") == 0) {
switch (category) {
case LC_ALL: {
_locale.decimal_point = "."; // fuck the french, the german, the russians and the rest of the wrongthinkers
_locale.thousands_sep = "";
_locale.grouping = "";
_locale.mon_decimal_point = "";
_locale.mon_thousands_sep = "";
_locale.mon_grouping = "";
_locale.positive_sign = "";
_locale.negative_sign = "";
_locale.currency_symbol = "";
_locale.frac_digits = CHAR_MAX;
_locale.p_cs_precedes = CHAR_MAX;
_locale.n_cs_precedes = CHAR_MAX;
_locale.p_sep_by_space = CHAR_MAX;
_locale.n_sep_by_space = CHAR_MAX;
_locale.p_sign_posn = CHAR_MAX;
_locale.n_sign_posn = CHAR_MAX;
_locale.int_curr_symbol = "";
_locale.int_frac_digits = CHAR_MAX;
_locale.int_p_cs_precedes = CHAR_MAX;
_locale.int_n_cs_precedes = CHAR_MAX;
_locale.int_p_sep_by_space = CHAR_MAX;
_locale.int_n_sep_by_space = CHAR_MAX;
_locale.int_p_sign_posn = CHAR_MAX;
_locale.int_n_sign_posn = CHAR_MAX;
break;
}
default: return NULL;
}
} else {
return NULL;
}
memcpy(_locale_str, locale, locale_len);
return _locale_str;
}
struct lconv *localeconv(void) {
return &_locale;
}

View File

@ -1,140 +0,0 @@
double fabs(double x) {
union {double f; uint64_t i;} u = {x};
u.i &= -1ULL/2;
return u.f;
}
float fabsf(float x) {
union {float f; uint32_t i;} u = {x};
u.i &= 0x7fffffff;
return u.f;
}
long double fabsl(long double x) {
return fabs(x);
}
double fdim(double x, double y) {
if (isnan(x)) return x;
if (isnan(y)) return y;
return x > y ? x - y : 0;
}
float fdimf(float x, float y) {
if (isnan(x)) return x;
if (isnan(y)) return y;
return x > y ? x - y : 0;
}
long double fdiml(long double x, long double y) {
return fdim(x, y);
}
double fmax(double x, double y) {
if (isnan(x)) return y;
if (isnan(y)) return x;
/* handle signed zeros, see C99 Annex F.9.9.2 */
if (signbit(x) != signbit(y))
return signbit(x) ? y : x;
return x < y ? y : x;
}
float fmaxf(float x, float y) {
if (isnan(x)) return y;
if (isnan(y)) return x;
/* handle signed zeroes, see C99 Annex F.9.9.2 */
if (signbit(x) != signbit(y))
return signbit(x) ? y : x;
return x < y ? y : x;
}
long double fmaxl(long double x, long double y) {
return fmax(x, y);
}
double fmin(double x, double y) {
if (isnan(x)) return y;
if (isnan(y)) return x;
/* handle signed zeros, see C99 Annex F.9.9.2 */
if (signbit(x) != signbit(y))
return signbit(x) ? x : y;
return x < y ? x : y;
}
float fminf(float x, float y) {
if (isnan(x)) return y;
if (isnan(y)) return x;
/* handle signed zeros, see C99 Annex F.9.9.2 */
if (signbit(x) != signbit(y))
return signbit(x) ? x : y;
return x < y ? x : y;
}
long double fminl(long double x, long double y) {
return fmin(x, y);
}
#ifdef __CUIK__
#warning "Cuik doesn't support the FMA intrinsics... fix that NeGate"
double fma(double x, double y, double z) {
return (x * y) + z;
}
float fmaf(float x, float y, float z) {
return (x * y) + z;
}
long double fmal(long double x, long double y, long double z) {
return (x * y) + z;
}
double sqrt(double x) {
return 0.0;
}
float sqrtf(float x) {
return 0.0;
}
#else
double fma(double x, double y, double z) {
__m128d xd = _mm_set_sd(x);
__m128d yd = _mm_set_sd(y);
__m128d zd = _mm_set_sd(z);
__m128d rd = _mm_fmadd_sd(xd, yd, zd);
double res = _mm_cvtsd_f64(rd);
return res;
}
float fmaf(float x, float y, float z) {
__m128 xd = _mm_set_ss(x);
__m128 yd = _mm_set_ss(y);
__m128 zd = _mm_set_ss(z);
__m128 rd = _mm_fmadd_ss(xd, yd, zd);
float res = _mm_cvtss_f32(rd);
return res;
}
long double fmal(long double x, long double y, long double z) {
return fma(x, y, z);
}
double sqrt(double x) {
__m128d xd = _mm_set_sd(x);
__m128d yd = _mm_set_sd(0);
__m128d rd = _mm_sqrt_sd(xd, yd);
double res = _mm_cvtsd_f64(rd);
return res;
}
float sqrtf(float x) {
__m128 xd = _mm_set_ss(x);
__m128 rd = _mm_sqrt_ss(xd);
float res = _mm_cvtss_f32(rd);
return res;
}
long double sqrtl(long double x) {
return sqrt(x);
}
#endif

View File

@ -1,100 +0,0 @@
// This thing doesn't compile branchlessly on MSVC lmao
// This is a branchless version of fpclassify
// The way it works is by assuming the following structure of float class
// bit 2 | bit 1 | bit 0
// e n m
// e is 1 for infinities and nan, 0 otherwise
// n is 1 for normal numbers, 0 otherwise
// m is 1 for nan and subnormal numbers, 0 otherwise
// This leaves the following values for classes:
// 0 - FP_ZERO
// 1 - FP_SUBNORMAL
// 2 - FP_NORMAL
// 4 - FP_INFINITE
// 5 - FP_NAN
int _fpclassify(f64 x) {
// First, extract bits
u64 bits = F64_BITS(x);
i64 exp = F64_BEXP(bits);
i64 mant = F64_MANT(bits);
// Get the number that's only zero when exp = 0x7ff
i64 ee = F64_BEXP_MAX - exp;
// Invert it to get number that's 1 iff x is infinity or nan
i64 e = !(ee);
// The value (ee*exp) is zero in two cases:
// exp = 0x7ff, (infinities, nan)
// exp = 0 (zero, subnormal)
// We negate this to make it so that this value is 1 only if number is not
// normal
i64 nn = !(ee*exp);
// Negate the previous thing. Now n is 1 iff number is normal
i64 n = !nn;
// m is 1 if mantissa is nonzero and the number is not normal
i64 m = !!mant & nn;
// Construct the float class
return (e<<2) | (n<<1) | m;
}
// Same recipe as above, different constants
int _fpclassifyf(float x) {
u64 bits = F32_BITS(x);
i64 exp = F32_BEXP(bits);
i64 mant = F32_MANT(bits);
i64 ee = F32_BEXP_MAX - exp;
i64 e = !(ee);
i64 nn = !(ee*exp);
i64 n = !nn;
i64 m = !!mant & nn;
return (e<<2) | (n<<1) | m;
}
int _fpclassifyl(fl64 x) {
return _fpclassify((f64)x);
}
int _signbit(f64 x) {
return F64_BITS(x)>>63;
}
int _signbitf(float x) {
return F32_BITS(x)>>31;
}
int _signbitl(fl64 x) {
return _signbit((f64)x);
}
f64 copysign(f64 x, f64 y) {
u64 xbits = F64_BITS(x);
u64 ybits = F64_BITS(y);
xbits &= ~(UINT64_C(1)<<63);
xbits |= ybits & (UINT64_C(1)<<63);
return F64_CONS(xbits);
}
float copysignf(float x, float y) {
u32 xbits = F32_BITS(x);
u32 ybits = F32_BITS(y);
xbits &= ~(UINT32_C(1)<<31);
xbits |= ybits & (1u<<31);
return F64_CONS(xbits);
}
fl64 copysignl(fl64 x, fl64 y) {
return copysign((f64)x, (f64)y);
}
f64 nan(const char *s) {
return NAN;
}
float nanf(const char *s) {
return NAN;
}
fl64 nanl(const char *s) {
return NAN;
}

View File

@ -1,202 +0,0 @@
double tK = 0x1.b7b2b62cef828p-1;
double hK = 0x1.a2166ada47ca4p-1;
double ttable[] = {
0x1.dac670561bb4fp-2,
0x1.f5b75f92c80ddp-3,
0x1.fd5ba9aac2f6ep-4,
0x1.ff55bb72cfdeap-5,
0x1.ffd55bba97625p-6,
0x1.fff555bbb729bp-7,
0x1.fffd555bbba97p-8,
0x1.ffff5555bbbb7p-9,
0x1.ffffd5555bbbcp-10,
0x1.fffff55555bbcp-11,
0x1.fffffd55555bcp-12,
0x1.ffffff555555cp-13,
0x1.ffffffd555556p-14,
0x1.fffffff555555p-15,
0x1.fffffffd55555p-16,
0x1.ffffffff55555p-17,
0x1.ffffffffd5555p-18,
0x1.fffffffff5555p-19,
0x1.fffffffffd555p-20,
0x1.ffffffffff555p-21,
0x1.ffffffffffd55p-22,
0x1.fffffffffff55p-23,
0x1.fffffffffffd5p-24,
0x1.ffffffffffff5p-25,
0x1.ffffffffffffdp-26,
0x1.fffffffffffffp-27,
0x1.0000000000000p-27,
0x1.0000000000000p-28,
0x1.0000000000000p-29,
0x1.0000000000000p-30,
0x1.0000000000000p-31,
0x1.0000000000000p-32,
0x1.0000000000000p-33,
0x1.0000000000000p-34,
0x1.0000000000000p-35,
0x1.0000000000000p-36,
0x1.0000000000000p-37,
0x1.0000000000000p-38,
0x1.0000000000000p-39,
0x1.0000000000000p-40,
0x1.0000000000000p-41,
0x1.0000000000000p-42,
0x1.0000000000000p-43,
0x1.0000000000000p-44,
0x1.0000000000000p-45,
0x1.0000000000000p-46,
0x1.0000000000000p-47,
0x1.0000000000000p-48,
0x1.0000000000000p-49,
0x1.0000000000000p-50,
0x1.0000000000000p-51,
0x1.0000000000000p-52,
0x1.0000000000000p-53,
0x1.0000000000000p-54,
0x1.0000000000000p-55,
0x1.0000000000000p-56,
0x1.0000000000000p-57,
0x1.0000000000000p-58,
0x1.0000000000000p-59,
0x1.0000000000000p-60,
0x1.0000000000000p-61,
0x1.0000000000000p-62,
0x1.0000000000000p-63,
};
double htable[] = {
0x1.193ea7aad030bp-1,
0x1.058aefa811452p-2,
0x1.015891c9eaef8p-3,
0x1.005588ad375adp-4,
0x1.001558891aee2p-5,
0x1.000555888ad1dp-6,
0x1.000155588891bp-7,
0x1.000055558888bp-8,
0x1.0000155558889p-9,
0x1.0000055555889p-10,
0x1.0000015555589p-11,
0x1.0000005555559p-12,
0x1.0000001555556p-13,
0x1.0000000555555p-14,
0x1.0000000155555p-15,
0x1.0000000055555p-16,
0x1.0000000015555p-17,
0x1.0000000005555p-18,
0x1.0000000001555p-19,
0x1.0000000000555p-20,
0x1.0000000000155p-21,
0x1.0000000000055p-22,
0x1.0000000000015p-23,
0x1.0000000000005p-24,
0x1.0000000000001p-25,
0x1.0000000000000p-26,
0x1.0000000000000p-27,
0x1.0000000000000p-28,
0x1.0000000000000p-29,
0x1.0000000000000p-30,
0x1.0000000000000p-31,
0x1.0000000000000p-32,
0x1.0000000000000p-33,
0x1.0000000000000p-34,
0x1.0000000000000p-35,
0x1.0000000000000p-36,
0x1.0000000000000p-37,
0x1.0000000000000p-38,
0x1.0000000000000p-39,
0x1.0000000000000p-40,
0x1.0000000000000p-41,
0x1.0000000000000p-42,
0x1.0000000000000p-43,
0x1.0000000000000p-44,
0x1.0000000000000p-45,
0x1.0000000000000p-46,
0x1.0000000000000p-47,
0x1.0000000000000p-48,
0x1.0000000000000p-49,
0x1.0000000000000p-50,
0x1.0000000000000p-51,
0x1.0000000000000p-52,
0x1.0000000000000p-53,
0x1.0000000000000p-54,
0x1.0000000000000p-55,
0x1.0000000000000p-56,
0x1.0000000000000p-57,
0x1.0000000000000p-58,
0x1.0000000000000p-59,
0x1.0000000000000p-60,
0x1.0000000000000p-61,
0x1.0000000000000p-62,
0x1.0000000000000p-63,
};
double ptable[] = {
0x1.0000000000000p-1,
0x1.0000000000000p-2,
0x1.0000000000000p-3,
0x1.0000000000000p-4,
0x1.0000000000000p-5,
0x1.0000000000000p-6,
0x1.0000000000000p-7,
0x1.0000000000000p-8,
0x1.0000000000000p-9,
0x1.0000000000000p-10,
0x1.0000000000000p-11,
0x1.0000000000000p-12,
0x1.0000000000000p-13,
0x1.0000000000000p-14,
0x1.0000000000000p-15,
0x1.0000000000000p-16,
0x1.0000000000000p-17,
0x1.0000000000000p-18,
0x1.0000000000000p-19,
0x1.0000000000000p-20,
0x1.0000000000000p-21,
0x1.0000000000000p-22,
0x1.0000000000000p-23,
0x1.0000000000000p-24,
0x1.0000000000000p-25,
0x1.0000000000000p-26,
0x1.0000000000000p-27,
0x1.0000000000000p-28,
0x1.0000000000000p-29,
0x1.0000000000000p-30,
0x1.0000000000000p-31,
0x1.0000000000000p-32,
0x1.0000000000000p-33,
0x1.0000000000000p-34,
0x1.0000000000000p-35,
0x1.0000000000000p-36,
0x1.0000000000000p-37,
0x1.0000000000000p-38,
0x1.0000000000000p-39,
0x1.0000000000000p-40,
0x1.0000000000000p-41,
0x1.0000000000000p-42,
0x1.0000000000000p-43,
0x1.0000000000000p-44,
0x1.0000000000000p-45,
0x1.0000000000000p-46,
0x1.0000000000000p-47,
0x1.0000000000000p-48,
0x1.0000000000000p-49,
0x1.0000000000000p-50,
0x1.0000000000000p-51,
0x1.0000000000000p-52,
0x1.0000000000000p-53,
0x1.0000000000000p-54,
0x1.0000000000000p-55,
0x1.0000000000000p-56,
0x1.0000000000000p-57,
0x1.0000000000000p-58,
0x1.0000000000000p-59,
0x1.0000000000000p-60,
0x1.0000000000000p-61,
0x1.0000000000000p-62,
0x1.0000000000000p-63,
};

View File

@ -1,106 +0,0 @@
float tKf = 0x1.b7b2b62cef828p-1;
float hKf = 0x1.a2166ada47ca4p-1;
float ttablef[] = {
0x1.dac670561bb4fp-2,
0x1.f5b75f92c80ddp-3,
0x1.fd5ba9aac2f6ep-4,
0x1.ff55bb72cfdeap-5,
0x1.ffd55bba97625p-6,
0x1.fff555bbb729bp-7,
0x1.fffd555bbba97p-8,
0x1.ffff5555bbbb7p-9,
0x1.ffffd5555bbbcp-10,
0x1.fffff55555bbcp-11,
0x1.fffffd55555bcp-12,
0x1.ffffff555555cp-13,
0x1.ffffffd555556p-14,
0x1.fffffff555555p-15,
0x1.fffffffd55555p-16,
0x1.ffffffff55555p-17,
0x1.ffffffffd5555p-18,
0x1.fffffffff5555p-19,
0x1.fffffffffd555p-20,
0x1.ffffffffff555p-21,
0x1.ffffffffffd55p-22,
0x1.fffffffffff55p-23,
0x1.fffffffffffd5p-24,
0x1.ffffffffffff5p-25,
0x1.ffffffffffffdp-26,
0x1.fffffffffffffp-27,
0x1.0000000000000p-27,
0x1.0000000000000p-28,
0x1.0000000000000p-29,
0x1.0000000000000p-30,
0x1.0000000000000p-31,
};
float htablef[] = {
0x1.193ea7aad030bp-1,
0x1.058aefa811452p-2,
0x1.015891c9eaef8p-3,
0x1.005588ad375adp-4,
0x1.001558891aee2p-5,
0x1.000555888ad1dp-6,
0x1.000155588891bp-7,
0x1.000055558888bp-8,
0x1.0000155558889p-9,
0x1.0000055555889p-10,
0x1.0000015555589p-11,
0x1.0000005555559p-12,
0x1.0000001555556p-13,
0x1.0000000555555p-14,
0x1.0000000155555p-15,
0x1.0000000055555p-16,
0x1.0000000015555p-17,
0x1.0000000005555p-18,
0x1.0000000001555p-19,
0x1.0000000000555p-20,
0x1.0000000000155p-21,
0x1.0000000000055p-22,
0x1.0000000000015p-23,
0x1.0000000000005p-24,
0x1.0000000000001p-25,
0x1.0000000000000p-26,
0x1.0000000000000p-27,
0x1.0000000000000p-28,
0x1.0000000000000p-29,
0x1.0000000000000p-30,
0x1.0000000000000p-31,
};
float ptablef[] = {
0x1.0000000000000p-1,
0x1.0000000000000p-2,
0x1.0000000000000p-3,
0x1.0000000000000p-4,
0x1.0000000000000p-5,
0x1.0000000000000p-6,
0x1.0000000000000p-7,
0x1.0000000000000p-8,
0x1.0000000000000p-9,
0x1.0000000000000p-10,
0x1.0000000000000p-11,
0x1.0000000000000p-12,
0x1.0000000000000p-13,
0x1.0000000000000p-14,
0x1.0000000000000p-15,
0x1.0000000000000p-16,
0x1.0000000000000p-17,
0x1.0000000000000p-18,
0x1.0000000000000p-19,
0x1.0000000000000p-20,
0x1.0000000000000p-21,
0x1.0000000000000p-22,
0x1.0000000000000p-23,
0x1.0000000000000p-24,
0x1.0000000000000p-25,
0x1.0000000000000p-26,
0x1.0000000000000p-27,
0x1.0000000000000p-28,
0x1.0000000000000p-29,
0x1.0000000000000p-30,
0x1.0000000000000p-31,
};

View File

@ -1,202 +0,0 @@
long double tKl = 0x1.b7b2b62cef828p-1;
long double hKl = 0x1.a2166ada47ca4p-1;
long double ttablel[] = {
0x1.dac670561bb4fp-2,
0x1.f5b75f92c80ddp-3,
0x1.fd5ba9aac2f6ep-4,
0x1.ff55bb72cfdeap-5,
0x1.ffd55bba97625p-6,
0x1.fff555bbb729bp-7,
0x1.fffd555bbba97p-8,
0x1.ffff5555bbbb7p-9,
0x1.ffffd5555bbbcp-10,
0x1.fffff55555bbcp-11,
0x1.fffffd55555bcp-12,
0x1.ffffff555555cp-13,
0x1.ffffffd555556p-14,
0x1.fffffff555555p-15,
0x1.fffffffd55555p-16,
0x1.ffffffff55555p-17,
0x1.ffffffffd5555p-18,
0x1.fffffffff5555p-19,
0x1.fffffffffd555p-20,
0x1.ffffffffff555p-21,
0x1.ffffffffffd55p-22,
0x1.fffffffffff55p-23,
0x1.fffffffffffd5p-24,
0x1.ffffffffffff5p-25,
0x1.ffffffffffffdp-26,
0x1.fffffffffffffp-27,
0x1.0000000000000p-27,
0x1.0000000000000p-28,
0x1.0000000000000p-29,
0x1.0000000000000p-30,
0x1.0000000000000p-31,
0x1.0000000000000p-32,
0x1.0000000000000p-33,
0x1.0000000000000p-34,
0x1.0000000000000p-35,
0x1.0000000000000p-36,
0x1.0000000000000p-37,
0x1.0000000000000p-38,
0x1.0000000000000p-39,
0x1.0000000000000p-40,
0x1.0000000000000p-41,
0x1.0000000000000p-42,
0x1.0000000000000p-43,
0x1.0000000000000p-44,
0x1.0000000000000p-45,
0x1.0000000000000p-46,
0x1.0000000000000p-47,
0x1.0000000000000p-48,
0x1.0000000000000p-49,
0x1.0000000000000p-50,
0x1.0000000000000p-51,
0x1.0000000000000p-52,
0x1.0000000000000p-53,
0x1.0000000000000p-54,
0x1.0000000000000p-55,
0x1.0000000000000p-56,
0x1.0000000000000p-57,
0x1.0000000000000p-58,
0x1.0000000000000p-59,
0x1.0000000000000p-60,
0x1.0000000000000p-61,
0x1.0000000000000p-62,
0x1.0000000000000p-63,
};
long double htablel[] = {
0x1.193ea7aad030bp-1,
0x1.058aefa811452p-2,
0x1.015891c9eaef8p-3,
0x1.005588ad375adp-4,
0x1.001558891aee2p-5,
0x1.000555888ad1dp-6,
0x1.000155588891bp-7,
0x1.000055558888bp-8,
0x1.0000155558889p-9,
0x1.0000055555889p-10,
0x1.0000015555589p-11,
0x1.0000005555559p-12,
0x1.0000001555556p-13,
0x1.0000000555555p-14,
0x1.0000000155555p-15,
0x1.0000000055555p-16,
0x1.0000000015555p-17,
0x1.0000000005555p-18,
0x1.0000000001555p-19,
0x1.0000000000555p-20,
0x1.0000000000155p-21,
0x1.0000000000055p-22,
0x1.0000000000015p-23,
0x1.0000000000005p-24,
0x1.0000000000001p-25,
0x1.0000000000000p-26,
0x1.0000000000000p-27,
0x1.0000000000000p-28,
0x1.0000000000000p-29,
0x1.0000000000000p-30,
0x1.0000000000000p-31,
0x1.0000000000000p-32,
0x1.0000000000000p-33,
0x1.0000000000000p-34,
0x1.0000000000000p-35,
0x1.0000000000000p-36,
0x1.0000000000000p-37,
0x1.0000000000000p-38,
0x1.0000000000000p-39,
0x1.0000000000000p-40,
0x1.0000000000000p-41,
0x1.0000000000000p-42,
0x1.0000000000000p-43,
0x1.0000000000000p-44,
0x1.0000000000000p-45,
0x1.0000000000000p-46,
0x1.0000000000000p-47,
0x1.0000000000000p-48,
0x1.0000000000000p-49,
0x1.0000000000000p-50,
0x1.0000000000000p-51,
0x1.0000000000000p-52,
0x1.0000000000000p-53,
0x1.0000000000000p-54,
0x1.0000000000000p-55,
0x1.0000000000000p-56,
0x1.0000000000000p-57,
0x1.0000000000000p-58,
0x1.0000000000000p-59,
0x1.0000000000000p-60,
0x1.0000000000000p-61,
0x1.0000000000000p-62,
0x1.0000000000000p-63,
};
long double ptablel[] = {
0x1.0000000000000p-1,
0x1.0000000000000p-2,
0x1.0000000000000p-3,
0x1.0000000000000p-4,
0x1.0000000000000p-5,
0x1.0000000000000p-6,
0x1.0000000000000p-7,
0x1.0000000000000p-8,
0x1.0000000000000p-9,
0x1.0000000000000p-10,
0x1.0000000000000p-11,
0x1.0000000000000p-12,
0x1.0000000000000p-13,
0x1.0000000000000p-14,
0x1.0000000000000p-15,
0x1.0000000000000p-16,
0x1.0000000000000p-17,
0x1.0000000000000p-18,
0x1.0000000000000p-19,
0x1.0000000000000p-20,
0x1.0000000000000p-21,
0x1.0000000000000p-22,
0x1.0000000000000p-23,
0x1.0000000000000p-24,
0x1.0000000000000p-25,
0x1.0000000000000p-26,
0x1.0000000000000p-27,
0x1.0000000000000p-28,
0x1.0000000000000p-29,
0x1.0000000000000p-30,
0x1.0000000000000p-31,
0x1.0000000000000p-32,
0x1.0000000000000p-33,
0x1.0000000000000p-34,
0x1.0000000000000p-35,
0x1.0000000000000p-36,
0x1.0000000000000p-37,
0x1.0000000000000p-38,
0x1.0000000000000p-39,
0x1.0000000000000p-40,
0x1.0000000000000p-41,
0x1.0000000000000p-42,
0x1.0000000000000p-43,
0x1.0000000000000p-44,
0x1.0000000000000p-45,
0x1.0000000000000p-46,
0x1.0000000000000p-47,
0x1.0000000000000p-48,
0x1.0000000000000p-49,
0x1.0000000000000p-50,
0x1.0000000000000p-51,
0x1.0000000000000p-52,
0x1.0000000000000p-53,
0x1.0000000000000p-54,
0x1.0000000000000p-55,
0x1.0000000000000p-56,
0x1.0000000000000p-57,
0x1.0000000000000p-58,
0x1.0000000000000p-59,
0x1.0000000000000p-60,
0x1.0000000000000p-61,
0x1.0000000000000p-62,
0x1.0000000000000p-63,
};

View File

@ -1,58 +0,0 @@
import math;
import os;
import sys;
abspath = os.path.abspath(sys.argv[0])
dname = os.path.dirname(abspath)
os.chdir(dname)
data=[
('cordic_dataf.h', 'float', 'f', 32),
('cordic_data.h', 'double', '', 64),
('cordic_datal.h', 'long double', 'l', 64),
]
for f in data:
fname = f[0]
ftype = f[1]
s = f[2]
N = f[3]
f = open(fname, 'w')
tK = 1
for i in range(1, N):
tK *= math.cos(math.atan(2**(-i)));
f.write(ftype + ' tK' + s + ' = ' + float.hex(tK) + ';\n')
f.write('\n')
hK = 1
for i in range(1, N):
hK *= math.cos(math.atanh(2**(-i)));
f.write(ftype + ' hK' + s + ' = ' + float.hex(hK) + ';\n')
f.write('\n')
f.write(ftype + ' ttable' + s + '[] = {\n');
for i in range(1, N):
v = math.atan(2**(-i));
f.write(' ' + float.hex(v) + ',\n')
f.write('};\n')
f.write('\n')
f.write(ftype + ' htable' + s + '[] = {\n');
for i in range(1, N):
v = math.atanh(2**(-i));
f.write(' ' + float.hex(v) + ',\n')
f.write('};\n')
f.write('\n')
f.write(ftype + ' ptable' + s + '[] = {\n');
for i in range(1, N):
v = 2**(-i);
f.write(' ' + float.hex(v) + ',\n')
f.write('};\n')
f.write('\n')
f.close();

View File

@ -1,248 +0,0 @@
double remquo(double x, double y, int *quo) {
union {double f; uint64_t i;} ux = {x}, uy = {y};
int ex = ux.i>>52 & 0x7ff;
int ey = uy.i>>52 & 0x7ff;
int sx = ux.i>>63;
int sy = uy.i>>63;
uint32_t q;
uint64_t i;
uint64_t uxi = ux.i;
*quo = 0;
if (uy.i<<1 == 0 || isnan(y) || ex == 0x7ff)
return (x*y)/(x*y);
if (ux.i<<1 == 0)
return x;
/* normalize x and y */
if (!ex) {
for (i = uxi<<12; i>>63 == 0; ex--, i <<= 1);
uxi <<= -ex + 1;
} else {
uxi &= -1ULL >> 12;
uxi |= 1ULL << 52;
}
if (!ey) {
for (i = uy.i<<12; i>>63 == 0; ey--, i <<= 1);
uy.i <<= -ey + 1;
} else {
uy.i &= -1ULL >> 12;
uy.i |= 1ULL << 52;
}
q = 0;
if (ex < ey) {
if (ex+1 == ey)
goto end;
return x;
}
/* x mod y */
for (; ex > ey; ex--) {
i = uxi - uy.i;
if (i >> 63 == 0) {
uxi = i;
q++;
}
uxi <<= 1;
q <<= 1;
}
i = uxi - uy.i;
if (i >> 63 == 0) {
uxi = i;
q++;
}
if (uxi == 0)
ex = -60;
else
for (; uxi>>52 == 0; uxi <<= 1, ex--);
end:
/* scale result and decide between |x| and |x|-|y| */
if (ex > 0) {
uxi -= 1ULL << 52;
uxi |= (uint64_t)ex << 52;
} else {
uxi >>= -ex + 1;
}
ux.i = uxi;
x = ux.f;
if (sy)
y = -y;
if (ex == ey || (ex+1 == ey && (2*x > y || (2*x == y && q%2)))) {
x -= y;
q++;
}
q &= 0x7fffffff;
*quo = sx^sy ? -(int)q : (int)q;
return sx ? -x : x;
}
float remquof(float x, float y, int *quo) {
union {float f; uint32_t i;} ux = {x}, uy = {y};
int ex = ux.i>>23 & 0xff;
int ey = uy.i>>23 & 0xff;
int sx = ux.i>>31;
int sy = uy.i>>31;
uint32_t q;
uint32_t i;
uint32_t uxi = ux.i;
*quo = 0;
if (uy.i<<1 == 0 || isnan(y) || ex == 0xff)
return (x*y)/(x*y);
if (ux.i<<1 == 0)
return x;
/* normalize x and y */
if (!ex) {
for (i = uxi<<9; i>>31 == 0; ex--, i <<= 1);
uxi <<= -ex + 1;
} else {
uxi &= -1U >> 9;
uxi |= 1U << 23;
}
if (!ey) {
for (i = uy.i<<9; i>>31 == 0; ey--, i <<= 1);
uy.i <<= -ey + 1;
} else {
uy.i &= -1U >> 9;
uy.i |= 1U << 23;
}
q = 0;
if (ex < ey) {
if (ex+1 == ey)
goto end;
return x;
}
/* x mod y */
for (; ex > ey; ex--) {
i = uxi - uy.i;
if (i >> 31 == 0) {
uxi = i;
q++;
}
uxi <<= 1;
q <<= 1;
}
i = uxi - uy.i;
if (i >> 31 == 0) {
uxi = i;
q++;
}
if (uxi == 0)
ex = -30;
else
for (; uxi>>23 == 0; uxi <<= 1, ex--);
end:
/* scale result and decide between |x| and |x|-|y| */
if (ex > 0) {
uxi -= 1U << 23;
uxi |= (uint32_t)ex << 23;
} else {
uxi >>= -ex + 1;
}
ux.i = uxi;
x = ux.f;
if (sy)
y = -y;
if (ex == ey || (ex+1 == ey && (2*x > y || (2*x == y && q%2)))) {
x -= y;
q++;
}
q &= 0x7fffffff;
*quo = sx^sy ? -(int)q : (int)q;
return sx ? -x : x;
}
long double remquol(long double x, long double y, int *quo) {
return remquo(x, y, quo);
}
double remainder(double x, double y) {
int q;
return remquo(x, y, &q);
}
float remainderf(float x, float y) {
int q;
return remquof(x, y, &q);
}
long double remainderl(long double x, long double y) {
return remainder(x, y);
}
double modf(double x, double *iptr) {
union {double f; uint64_t i;} u = {x};
uint64_t mask;
int e = (int)(u.i>>52 & 0x7ff) - 0x3ff;
/* no fractional part */
if (e >= 52) {
*iptr = x;
if (e == 0x400 && u.i<<12 != 0) /* nan */
return x;
u.i &= 1ULL<<63;
return u.f;
}
/* no integral part*/
if (e < 0) {
u.i &= 1ULL<<63;
*iptr = u.f;
return x;
}
mask = -1ULL>>12>>e;
if ((u.i & mask) == 0) {
*iptr = x;
u.i &= 1ULL<<63;
return u.f;
}
u.i &= ~mask;
*iptr = u.f;
return x - u.f;
}
float modff(float x, float *iptr) {
union {float f; uint32_t i;} u = {x};
uint32_t mask;
int e = (int)(u.i>>23 & 0xff) - 0x7f;
/* no fractional part */
if (e >= 23) {
*iptr = x;
if (e == 0x80 && u.i<<9 != 0) { /* nan */
return x;
}
u.i &= 0x80000000;
return u.f;
}
/* no integral part */
if (e < 0) {
u.i &= 0x80000000;
*iptr = u.f;
return x;
}
mask = 0x007fffff>>e;
if ((u.i & mask) == 0) {
*iptr = x;
u.i &= 0x80000000;
return u.f;
}
u.i &= ~mask;
*iptr = u.f;
return x - u.f;
}
long double modfl(long double x, long double *iptr) {
double d;
long double r = modf(x, &d);
*iptr = d;
return r;
}

View File

@ -1,28 +0,0 @@
static double LN2 = 0.693147180559945309417232121458176;
static double HALF_PI = 1.570796326794896619231321691639751;
static double PI = 3.141592653589793238462643383279502;
static double LOG2E = 1.442695040888963407359924681001892;
#define countof(arr) (sizeof arr/sizeof arr[0])
#define ftype float
#define suffix(name) name ## f
#include "cordic/cordic_dataf.h"
#include "gen_math.h"
#undef ftype
#undef suffix
#define ftype double
#define suffix(name) name
#include "cordic/cordic_data.h"
#include "gen_math.h"
#undef ftype
#undef suffix
#define ftype long double
#define suffix(name) name ## l
#include "cordic/cordic_datal.h"
#include "gen_math.h"
#undef ftype
#undef suffix

View File

@ -1,228 +0,0 @@
static ftype suffix(cordic)(
ftype x0, // x initial value
ftype y0, // y initial value
ftype z0, // initial 'angle'
int m, // system: 1 for trig, -1 for hyperbolic
int v, // mode: 1 for vectoring, 0 for rotation
ftype *c, // output x
ftype *s // output y
) {
int tab_count = 0;
ftype *tab = NULL;
if(m == 1) {
tab = suffix(ttable);
tab_count = countof(suffix(ttable));
}
else if(m == -1) {
tab = suffix(htable);
tab_count = countof(suffix(htable));
}
ftype x = x0;
ftype y = y0;
ftype z = z0;
for(int i = 0; i != tab_count; ++i) {
ftype sign;
if(v) sign = (y < 0)? 1 : -1;
else sign = (z < 0)? -1 : 1;
ftype x1 = suffix(fma)(suffix(ptable)[i], -m*sign*y, x);
ftype y1 = suffix(fma)(suffix(ptable)[i], x*sign, y);
x = x1;
y = y1;
z = suffix(fma)(tab[i], -sign, z);
}
if(c!=NULL) *c = x;
if(s!=NULL) *s = y;
return z;
}
ftype suffix(sin)(ftype x) {
if(isinf(x)) return NAN;
if(isnan(x)) return NAN;
int k;
ftype alpha = suffix(remquo)(x, HALF_PI, &k);
if(x == 0) return x;
k = (((k % 4) +4) %4);
ftype sinx;
ftype cosx;
suffix(cordic)(suffix(tK), 0, alpha, 1, 0, &cosx, &sinx);
switch(k) {
case 0: return sinx;
case 1: return cosx;
case 2: return -sinx;
case 3: return -cosx;
}
return 0;
}
ftype suffix(cos)(ftype x) {
if(isinf(x)) return NAN;
if(isnan(x)) return NAN;
int k;
ftype alpha = suffix(remquo)(x, HALF_PI, &k);
k = (((k % 4) +4) %4);
ftype sinx;
ftype cosx;
suffix(cordic)(suffix(tK), 0, alpha, 1, 0, &cosx, &sinx);
switch(k) {
case 0: return cosx;
case 1: return -sinx;
case 2: return -cosx;
case 3: return sinx;
}
return 0;
}
ftype suffix(tan)(ftype x) {
if(isinf(x)) return NAN;
if(isnan(x)) return NAN;
int k;
ftype alpha = suffix(remquo)(x, HALF_PI, &k);
if(x == 0) return x;
k = (((k % 2) +2) %2);
ftype sinx;
ftype cosx;
suffix(cordic)(suffix(tK), 0, alpha, 1, 0, &cosx, &sinx);
switch(k) {
case 0: return sinx/cosx;
case 1: return -cosx/sinx;
}
return 0;
}
ftype suffix(cot)(ftype x) {
if(x == 0) return x;
if(isinf(x)) return NAN;
if(isnan(x)) return NAN;
int k;
ftype alpha = suffix(remquo)(x, HALF_PI, &k);
k = (((k % 2) +2) %2);
ftype sinx;
ftype cosx;
suffix(cordic)(suffix(tK), 0, alpha, 1, 0, &cosx, &sinx);
switch(k) {
case 0: return cosx/sinx;
case 1: return -sinx/cosx;
}
return 0;
}
ftype suffix(exp)(ftype x) {
if(x == 0) return x;
if(isinf(x)) return NAN;
if(isnan(x)) return NAN;
ftype t = x*LOG2E;
int64_t k = (int64_t)t;
x = (t - (ftype)k) / LOG2E;
ftype xx = x*x;
ftype xxx = xx*x;
ftype xxxx = xx*xx;
ftype xxxxx = xxx*xx;
ftype expx = 1+x + xx/2.0 + xxx/6.0+ xxxx/24.0 + xxxxx/720.0;
if(k>0) expx *= 2.0;
if(k>0) while(k-- > 0) expx *= 2.0;
if(k<0) while(k++ < 0) expx /= 2.0;
return expx;
}
ftype suffix(atan)(ftype x) {
if(x == 0) return x;
if(isinf(x)) return INFINITY;
if(isnan(x)) return NAN;
ftype atan;
if(x > 1) {
atan = HALF_PI - suffix(cordic)(x, 1, 0, 1, 1, NULL, NULL);
}
else if(x < -1) {
atan = -HALF_PI + suffix(cordic)(-x, 1, 0, 1, 1, NULL, NULL);
}
else {
atan = suffix(cordic)(1, x, 0, 1, 1, NULL, NULL);
}
return atan;
}
ftype suffix(acos)(ftype x) {
if(x == 0) return HALF_PI;
if(x == -1) return PI;
if(x == 1) return 0;
if(isinf(x)) return INFINITY;
if(isnan(x)) return NAN;
if(fabs(x) > 1) return NAN;
ftype atan;
x = sqrt(fma(-x,x,1))/x;
if(x > 1) {
atan = HALF_PI - suffix(cordic)(x, 1, 0, 1, 1, NULL, NULL);
}
else if(x < -1) {
atan = -HALF_PI + suffix(cordic)(-x, 1, 0, 1, 1, NULL, NULL);
}
else {
atan = suffix(cordic)(1, x, 0, 1, 1, NULL, NULL);
}
if(x < 0) atan += PI;
return atan;
}
ftype suffix(asin)(ftype x) {
if(x == 0) return 0;
if(x == -1) return -HALF_PI;
if(x == 1) return HALF_PI;
if(isinf(x)) return INFINITY;
if(isnan(x)) return NAN;
if(fabs(x) > 1) return NAN;
ftype atan;
x /= sqrt(fma(-x,x,1));
if(x > 1) {
atan = HALF_PI - suffix(cordic)(x, 1, 0, 1, 1, NULL, NULL);
}
else if(x < -1) {
atan = -HALF_PI + suffix(cordic)(-x, 1, 0, 1, 1, NULL, NULL);
}
else {
atan = suffix(cordic)(1, x, 0, 1, 1, NULL, NULL);
}
return atan;
}
// ftype suffix(exp)(ftype x) {
// if(isnan(x)) return NAN;
// if(x > 0 && isinf(x)) return +INFINITY;
// if(x < 0 && isinf(x)) return +0.0;
// if(x == 0) return 1.0;
// if(x > 709.8) {
// #if math_errhandling & MATH_ERREXCEPT
// feraiseexcept(FE_OVERFLOW);
// #endif
// #if math_errhandling & MATH_ERRNO
// errno = ERANGE;
// #endif
// return +INFINITY;
// }
// if(x < -708.4) {
// #if math_errhandling & MATH_ERREXCEPT
// feraiseexcept(FE_OVERFLOW);
// #endif
// #if math_errhandling & MATH_ERRNO
// errno = ERANGE;
// #endif
// return 0;
// }
// ftype e = 1.0;
// ftype xp = 1.0;
// ftype f = 1;
// for(uint64_t i = 1; i != 10; ++i) {
// f *= i;
// xp *= x;
// e += xp / f;
// }
// return e;
// }
ftype suffix(exp2)(ftype x) {
return suffix(exp)(x * LN2);
}
ftype suffix(expm1)(ftype x) {
return suffix(exp)(x) - 1.0;
}

View File

@ -1,522 +0,0 @@
#define asuint64(x) ((union {f64 f; uint64_t i;}){x}).i
#define asdouble(x) ((union {f64 f; uint64_t i;}){x}).f
#if defined(__GNUC__) || defined(__clang__)
#define just_do_it(v) do{__attribute__((unused)) volatile f64 t = v;}while(0)
#else
#define just_do_it(v) do{volatile f64 t = v;}while(0)
#endif
f64 nearbyint(f64 x) {
#pragma STDC FENV_ACCESS ON
u64 bits = F64_BITS(x);
i64 bexp = F64_BEXP(bits);
u64 bmant = F64_MANT(bits);
// 1. Get rid of special cases, exp = 0x7ff, and exp < 0x3ff
// Return x unmodified if inf, nan
if(bexp == 0x7ff) {
return x;
}
int mode = fegetround();
// Get exponent for (integer_mantissa * 2^exp) representation
i64 exp = bexp - 0x3ff - 52;
int s = F64_SIGN(bits);
// This value is 0 if no increment is required, and 1 if the absolute value
// increases by 1
int c;
{
// Check if we need to round towards 0 or towards 1
// (assumes specific values in rounding modes in fenv.h)
int a = (mode&2)>>1;
int b = mode&1;
int mask = ((a^b)<<1)|(a^b);
int d = 2 - mode&mask;
c = s ^ d;
}
// If the whole mantissa is after a point, such that the first digit is 0,
// then the value is closer to 0 these values are all zeroes, subnormal
// numbers and very small normal numbers
if(exp < -53) {
// Return 0 if exponent and mantissa are zero
if(bexp == 0 && bmant == 0) {
return x;
}
// For subnormal and normal numbers we round them either towards 0 or 1
// and then call it a day
u64 new_bexp = (u64)((1-c)&0x3ff) << F64_MANT_BITS;
u64 new_sign = (u64)s << 63;
u64 new_bits = new_sign | new_bexp;
return F64_CONS(new_bits);
}
// 2. Get fractional and whole bits of the mantissa
u64 mant = bmant | ((u64)1 << 52);
if(exp >= 0) {
// Already an integer
return x;
}
// if e.g. mantissa is 0b101.., and exponent is -2, the value is 0b101*2^-2
// or 0b1.01, meaning there are 2 fractional digits
int nfrac_digs = -exp;
u64 frac_mask = (((u64)1<<(nfrac_digs))-1);
u64 frac_mant = mant & frac_mask;
// The mantissas for 1.0 and 0.5
u64 one = (((u64)1<<(nfrac_digs)));
u64 half = one >> 1;
// 3. Round the float based on the value of c
// we'll first fix up c to include other rounding modes
c |= (mode == FE_UPWARD) & ((~s)&1);
c |= (mode == FE_DOWNWARD) & s;
c |= (mode == FE_TONEAREST) & (frac_mant >= half);
// Drop fractional bits
u64 new_mant = mant & ~frac_mant;
// Add 1 to float if required
if(c) {
new_mant += one;
if(new_mant > ((u64)1 << 53)) {
new_mant >>= 1;
exp += 1;
}
}
new_mant &= F64_MANT_MASK;
u64 new_bits = new_mant;
new_bits |= (exp+0x3ff+52) << F64_MANT_BITS;
new_bits |= (u64)s << (F64_MANT_BITS + F64_BEXP_BITS);
f64 result = F64_CONS(new_bits);
return result;
}
f32 nearbyintf(f32 x) {
#pragma STDC FENV_ACCESS ON
u64 bits = F32_BITS(x);
i64 bexp = F32_BEXP(bits);
u64 bmant = F32_MANT(bits);
if(bexp == 0x7f) {
return x;
}
int mode = fegetround();
i64 exp = bexp - 0x3f - 52;
int s = F32_SIGN(bits);
int c;
{
int a = (mode&2)>>1;
int b = mode&1;
int mask = ((a^b)<<1)|(a^b);
int d = 2 - mode&mask;
c = s ^ d;
}
if(exp < -24) {
if(bexp == 0 && bmant == 0) {
return x;
}
u64 new_bexp = (u64)((1-c)&0x3f) << F32_MANT_BITS;
u64 new_sign = (u64)s << 63;
u64 new_bits = new_sign | new_bexp;
return F32_CONS(new_bits);
}
u64 mant = bmant | ((u64)1 << 23);
if(exp >= 0) {
return x;
}
int nfrac_digs = -exp;
u64 frac_mask = (((u64)1<<(nfrac_digs))-1);
u64 frac_mant = mant & frac_mask;
u64 one = (((u64)1<<(nfrac_digs)));
u64 half = one >> 1;
c |= (mode == FE_UPWARD) & ((~s)&1);
c |= (mode == FE_DOWNWARD) & s;
c |= (mode == FE_TONEAREST) & (frac_mant >= half);
u64 new_mant = mant & ~frac_mant;
if(c) {
new_mant += one;
if(new_mant > ((u64)1 << 24)) {
new_mant >>= 1;
exp += 1;
}
}
new_mant &= F32_MANT_MASK;
u64 new_bits = new_mant;
new_bits |= (exp+0x3f+23) << F32_MANT_BITS;
new_bits |= (u64)s << (F32_MANT_BITS + F32_BEXP_BITS);
f64 result = F32_CONS(new_bits);
return result;
}
fl64 nearbyintl(fl64 x) {
return nearbyint((f64)x);
}
f64 nextafter(f64 x, f64 y) {
union {f64 f; uint64_t i;} ux={x}, uy={y};
uint64_t ax, ay;
int e;
if (isnan(x) || isnan(y)) return x + y;
if (ux.i == uy.i) return y;
ax = ux.i & -1ULL/2;
ay = uy.i & -1ULL/2;
if (ax == 0) {
if (ay == 0) return y;
ux.i = (uy.i & 1ULL<<63) | 1;
} else if (ax > ay || ((ux.i ^ uy.i) & 1ULL<<63)) {
ux.i--;
}
else {
ux.i++;
}
e = ux.i >> 52 & 0x7f;
/* raise overflow if ux.f is infinite and x is finite */
if (e == 0x7f) just_do_it(x+x);
/* raise underflow if ux.f is subnormal or zero */
if (e == 0) just_do_it(x*x + ux.f*ux.f);
return ux.f;
}
f32 nextafterf(f32 x, f32 y) {
union {f32 f; uint32_t i;} ux={x}, uy={y};
uint32_t ax, ay, e;
if (isnan(x) || isnan(y)) return x + y;
if (ux.i == uy.i) return y;
ax = ux.i & 0x7fffffff;
ay = uy.i & 0x7fffffff;
if (ax == 0) {
if (ay == 0) return y;
ux.i = (uy.i & 0x80000000) | 1;
} else if (ax > ay || ((ux.i ^ uy.i) & 0x80000000)) {
ux.i--;
}
else {
ux.i++;
}
e = ux.i & 0x7f800000;
/* raise overflow if ux.f is infinite and x is finite */
if (e == 0x7f800000) just_do_it(x+x);
/* raise underflow if ux.f is subnormal or zero */
if (e == 0) just_do_it(x*x + ux.f*ux.f);
return ux.f;
}
fl64 nextafterl(fl64 x, fl64 y) {
return nextafter(x, y);
}
f64 nexttoward(f64 x, fl64 y) {
return nextafter(x, y);
}
f32 nexttowardf(f32 x, fl64 y) {
union {f32 f; uint32_t i;} ux = {x};
uint32_t e;
if (isnan(x) || isnan(y)) return x + y;
if (x == y) return y;
if (x == 0) {
ux.i = 1;
if (signbit(y)) ux.i |= 0x80000000;
} else if (x < y) {
if (signbit(x)) ux.i--;
else ux.i++;
} else {
if (signbit(x)) ux.i++;
else ux.i--;
}
e = ux.i & 0x7f800000;
/* raise overflow if ux.f is infinite and x is finite */
if (e == 0x7f800000) just_do_it(x+x);
/* raise underflow if ux.f is subnormal or zero */
if (e == 0) just_do_it(x*x + ux.f*ux.f);
return ux.f;
}
fl64 nexttowardl(fl64 x, fl64 y) {
return nextafterl(x, y);
}
f64 rint(f64 x) {
static const double_t toint = 1/DBL_EPSILON;
union {f64 f; uint64_t i;} u = {x};
int e = u.i>>52 & 0x7ff;
int s = u.i>>63;
f64 y;
if (e >= 0x3ff+52) return x;
if (s) y = x - toint + toint;
else y = x + toint - toint;
if (y == 0) return s ? -0.0 : +0.0;
return y;
}
f32 rintf(f32 x) {
static const f32 toint = 1/FLT_EPSILON;
union {f32 f; uint32_t i;} u = {x};
int e = u.i>>23 & 0xff;
int s = u.i>>31;
f32 y;
if (e >= 0x7f+23) return x;
if (s) y = x - toint + toint;
else y = x + toint - toint;
if (y == 0) return s ? -0.0f : 0.0f;
return y;
}
fl64 rintl(fl64 x) {
return rint(x);
}
#if LONG_MAX < 1U<<53 && defined(FE_INEXACT)
static long lrint_slow(f64 x)
{
#pragma STDC FENV_ACCESS ON
int e;
e = fetestexcept(FE_INEXACT);
x = rint(x);
if (!e && (x > LONG_MAX || x < LONG_MIN))
feclearexcept(FE_INEXACT);
/* conversion */
return x;
}
long lrint(f64 x)
{
uint32_t abstop = asuint64(x)>>32 & 0x7fffffff;
uint64_t sign = asuint64(x) & (1ULL << 63);
if (abstop < 0x41dfffff) {
/* |x| < 0x7ffffc00, no overflow */
double_t toint = asdouble(asuint64(1/DBL_EPSILON) | sign);
double_t y = x + toint - toint;
return (long)y;
}
return lrint_slow(x);
}
#else
long lrint(f64 x) {
return rint(x);
}
#endif
long lrintf(f32 x) {
return rintf(x);
}
long lrintl(fl64 x) {
return lrint(x);
}
long long llrint(f64 x) {
return rint(x);
}
long long llrintf(f32 x) {
return rintf(x);
}
long long llrintl(fl64 x) {
return llrint(x);
}
f64 round(f64 x) {
static const double_t toint = 1/DBL_EPSILON;
union {f64 f; uint64_t i;} u = {x};
int e = u.i >> 52 & 0x7ff;
double_t y;
if (e >= 0x3ff+52) return x;
if (u.i >> 63) x = -x;
if (e < 0x3ff-1) {
/* raise inexact if x!=0 */
just_do_it(x + toint);
return 0*u.f;
}
y = x + toint - toint - x;
if (y > 0.5) y = y + x - 1;
else if (y <= -0.5) y = y + x + 1;
else y = y + x;
if (u.i >> 63) y = -y;
return y;
}
f32 roundf(f32 x) {
static const double_t toint = 1/FLT_EPSILON;
union {f32 f; uint32_t i;} u = {x};
int e = u.i >> 23 & 0xff;
float_t y;
if (e >= 0x7f+23) return x;
if (u.i >> 31) x = -x;
if (e < 0x7f-1) {
just_do_it(x + toint);
return 0*u.f;
}
y = x + toint - toint - x;
if (y > 0.5f) y = y + x - 1;
else if (y <= -0.5f) y = y + x + 1;
else y = y + x;
if (u.i >> 31) y = -y;
return y;
}
fl64 roundl(fl64 x) {
return round(x);
}
long lround(f64 x) {
return round(x);
}
long lroundf(f32 x) {
return roundf(x);
}
long lroundl(fl64 x) {
return roundl(x);
}
long long llround(f64 x) {
return round(x);
}
long long llroundf(f32 x) {
return roundf(x);
}
long long llroundl(fl64 x) {
return roundl(x);
}
f64 ceil(f64 x) {
static const double_t toint = 1/DBL_EPSILON;
union {f64 f; uint64_t i;} u = {x};
int e = u.i >> 52 & 0x7ff;
double_t y;
if (e >= 0x3ff+52 || x == 0)
return x;
/* y = int(x) - x, where int(x) is an integer neighbor of x */
if (u.i >> 63)
y = x - toint + toint - x;
else
y = x + toint - toint - x;
/* special case because of non-nearest rounding modes */
if (e <= 0x3ff-1) {
just_do_it(y);
return u.i >> 63 ? -0.0 : 1;
}
if (y < 0)
return x + y + 1;
return x + y;
}
f32 ceilf(f32 x) {
union {f32 f; uint32_t i;} u = {x};
int e = (int)(u.i >> 23 & 0xff) - 0x7f;
uint32_t m;
if (e >= 23)
return x;
if (e >= 0) {
m = 0x007fffff >> e;
if ((u.i & m) == 0)
return x;
just_do_it(x + 0x1p120f);
if (u.i >> 31 == 0)
u.i += m;
u.i &= ~m;
} else {
just_do_it(x + 0x1p120f);
if (u.i >> 31)
u.f = -0.0;
else if (u.i << 1)
u.f = 1.0;
}
return u.f;
}
fl64 ceill(fl64 x) {
return ceil(x);
}
f64 floor(f64 x) {
static const double_t toint = 1/DBL_EPSILON;
union {f64 f; uint64_t i;} u = {x};
int e = u.i >> 52 & 0x7ff;
double_t y;
if (e >= 0x3ff+52 || x == 0)
return x;
/* y = int(x) - x, where int(x) is an integer neighbor of x */
if (u.i >> 63)
y = x - toint + toint - x;
else
y = x + toint - toint - x;
/* special case because of non-nearest rounding modes */
if (e <= 0x3ff-1) {
just_do_it(y);
return u.i >> 63 ? -1 : 0;
}
if (y > 0)
return x + y - 1;
return x + y;
}
f32 floorf(f32 x) {
union {f32 f; uint32_t i;} u = {x};
int e = (int)(u.i >> 23 & 0xff) - 0x7f;
uint32_t m;
if (e >= 23)
return x;
if (e >= 0) {
m = 0x007fffff >> e;
if ((u.i & m) == 0)
return x;
just_do_it(x + 0x1p120f);
if (u.i >> 31)
u.i += m;
u.i &= ~m;
} else {
just_do_it(x + 0x1p120f);
if (u.i >> 31 == 0)
u.i = 0;
else if (u.i << 1)
u.f = -1.0;
}
return u.f;
}
fl64 floorl(fl64 x) {
return floor(x);
}
f64 trunc(f64 x) {
union {f64 f; uint64_t i;} u = {x};
int e = (int)(u.i >> 52 & 0x7ff) - 0x3ff + 12;
uint64_t m;
if (e >= 52 + 12)
return x;
if (e < 12)
e = 1;
m = -1ULL >> e;
if ((u.i & m) == 0)
return x;
just_do_it(x + 0x1p120f);
u.i &= ~m;
return u.f;
}
f32 truncf(f32 x) {
union {f32 f; uint32_t i;} u = {x};
int e = (int)(u.i >> 23 & 0xff) - 0x7f + 9;
uint32_t m;
if (e >= 23 + 9)
return x;
if (e < 9)
e = 1;
m = -1U >> e;
if ((u.i & m) == 0)
return x;
just_do_it(x + 0x1p120f);
u.i &= ~m;
return u.f;
}
fl64 truncl(fl64 x) {
return trunc(x);
}

View File

@ -1,85 +0,0 @@
#include <fcntl.h>
#include <unistd.h>
// Exit routines
#define ATEXIT_FUNC_COUNT 64
#define ATQEXIT_FUNC_COUNT 64
static void (*atexit_funcs [ATEXIT_FUNC_COUNT])(void);
static void (*atqexit_funcs[ATQEXIT_FUNC_COUNT])(void);
static int atexit_func_count;
static int atqexit_func_count;
static char **get_command_args(int *argcp);
// TODO: Instead of using static arrays, allocate this memory dynamically
static char cmdline[4096];
static char *cmdargs[1024];
extern int main(int argc, char** argv);
void _start() {
srand(0);
setlocale(LC_ALL, "C");
int argc;
char **argv = get_command_args(&argc);
int exit_code = main(argc, argv);
exit(exit_code);
}
_Noreturn void quick_exit(int status) {
while(atqexit_func_count--) {
atqexit_funcs[atqexit_func_count]();
}
_exit(status);
}
_Noreturn void exit(int status) {
while(atexit_func_count--) {
atexit_funcs[atqexit_func_count]();
}
// _close_io();
_exit(status);
}
_Noreturn void _Exit(int status) {
_exit(status);
}
_Noreturn void abort(void) {
// raise(SIGABRT);
_exit(-69);
}
int atexit(void (*func)(void)) {
if (atexit_func_count >= ATEXIT_FUNC_COUNT) {
return 0;
}
atexit_funcs[atexit_func_count++] = func;
return 1;
}
int at_quick_exit(void (*func)(void)) {
if(atqexit_func_count >= ATQEXIT_FUNC_COUNT) {
return 0;
}
atqexit_funcs[atqexit_func_count++] = func;
return 1;
}
static char **get_command_args(int *argcp) {
int fd = open("/proc/self/cmdline", O_RDONLY);
ssize_t size = read(fd, cmdline, sizeof cmdline);
ssize_t i = 0;
ssize_t cmd_idx = 0;
while(i != size) {
cmdargs[cmd_idx] = &cmdline[i];
while(cmdline[i] != 0) {
++i;
}
++i;
}
return cmdargs;
}

View File

@ -1,9 +0,0 @@
bits 64
segment .text
global _exit
_exit:
mov rax, 60
syscall
ret

View File

@ -1,64 +0,0 @@
#include <assert.h>
#pragma comment(lib, "user32.lib")
#pragma comment(lib, "DbgHelp.lib")
static void _print_stack_trace() {
HANDLE process = GetCurrentProcess();
SymInitialize(process, NULL, TRUE);
void *stack[128];
USHORT frames = CaptureStackBackTrace(2, 128, stack, NULL);
SYMBOL_INFO* symbol = calloc(sizeof(SYMBOL_INFO)+256, 1);
symbol->MaxNameLen = 255;
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
for(size_t i = 0; i < frames; i++) {
SymFromAddr(process, (DWORD64)stack[i], 0, symbol);
// if(strcmp(symbol->Name, "BaseThreadInitThunk") == 0) break;
// if(strcmp(symbol->Name, "mainCRTStartup") == 0) break;
// printf(//" %u: 0x%"PRIx64" (%s)\n",
// " %d: %s\n",
// (int)(frames-i-1),
// //symbol->Address,
// symbol->Name
// );
}
free(symbol);
}
void _assert(
char const *cond,
char const *func,
char const *file,
int line
) {
if(GetConsoleWindow() == NULL) {
// For GUI application we display the info into a messagebox
char buf[1024];
int i = 0;
// i += snprintf(buf+i, sizeof buf-i, "Assertion failed: %s\n", cond);
// i += snprintf(buf+i, sizeof buf-i, " Function: %s\n", func);
// i += snprintf(buf+i, sizeof buf-i, " File: %s\n", file);
// i += snprintf(buf+i, sizeof buf-i, " Line: %d\n", line);
display_msg:
int reaction = MessageBoxA(NULL, buf, "Assertion Failed", 0x00000032L);
switch(reaction) {
case IDABORT: abort();
case IDRETRY: goto display_msg;
case IDCONTINUE: return;
}
}
else {
// For console application we print the info to console
// printf("Assertion failed: %s\n", cond);
// printf(" Function: %s\n", func);
// printf(" File: %s\n", file);
// printf(" Line: %d\n", line);
// printf("Trace:\n");
_print_stack_trace();
abort();
}
}

View File

@ -1,28 +0,0 @@
bits 64
segment .text
global __chkstk
__chkstk:
sub rsp, 0x10
mov [rsp], r10
mov [rsp+0x8], r11
xor r11, r11
lea r10, [rsp+0x18]
sub r10, rax
cmovb r10, r11
mov r11, gs:[0x10]
cmp r10, r11
jnb .end
and r10w, 0xf000
.loop:
lea r11, [r11-0x1000]
mov byte [r11], 0x0
cmp r10, r11
jnz .loop
.end:
mov r10, [rsp]
mov r11, [rsp+0x8]
add rsp, 0x10
ret

View File

@ -1,116 +0,0 @@
#define CMDLINE_CMD_MAX 32767
#define CMDLINE_ARGV_MAX (16384+(98298+(int)sizeof(char*))/(int)sizeof(char*))
// https://github.com/skeeto/scratch/blob/master/misc/cmdline.c#L27
static int cmdline_to_argv8(const wchar_t *cmd, char **argv) {
int argc = 1; // worst case: argv[0] is an empty string
int state = 6; // special argv[0] state
int slash = 0;
char *buf = (char *)(argv + 16384); // second half: byte buffer
argv[0] = buf;
while (*cmd) {
int c = *cmd++;
if (c>>10 == 0x36 && *cmd>>10 == 0x37) { // surrogates?
c = 0x10000 + ((c - 0xd800)<<10) + (*cmd++ - 0xdc00);
}
switch (state) {
case 0: switch (c) { // outside token
case 0x09:
case 0x20: continue;
case 0x22: argv[argc++] = buf;
state = 2;
continue;
case 0x5c: argv[argc++] = buf;
slash = 1;
state = 3;
break;
default : argv[argc++] = buf;
state = 1;
} break;
case 1: switch (c) { // inside unquoted token
case 0x09:
case 0x20: *buf++ = 0;
state = 0;
continue;
case 0x22: state = 2;
continue;
case 0x5c: slash = 1;
state = 3;
break;
} break;
case 2: switch (c) { // inside quoted token
case 0x22: state = 5;
continue;
case 0x5c: slash = 1;
state = 4;
break;
} break;
case 3:
case 4: switch (c) { // backslash sequence
case 0x22: buf -= (1 + slash) >> 1;
if (slash & 1) {
state -= 2;
break;
} // fallthrough
default : cmd--;
state -= 2;
continue;
case 0x5c: slash++;
} break;
case 5: switch (c) { // quoted token exit
default : cmd--;
state = 1;
continue;
case 0x22: state = 1;
} break;
case 6: switch (c) { // begin argv[0]
case 0x09:
case 0x20: *buf++ = 0;
state = 0;
continue;
case 0x22: state = 8;
continue;
default : state = 7;
} break;
case 7: switch (c) { // unquoted argv[0]
case 0x09:
case 0x20: *buf++ = 0;
state = 0;
continue;
} break;
case 8: switch (c) { // quoted argv[0]
case 0x22: *buf++ = 0;
state = 0;
continue;
} break;
}
switch (c & 0x1f0880) { // WTF-8/UTF-8 encoding
case 0x00000: *buf++ = 0x00 | ((c >> 0) ); break;
case 0x00080: *buf++ = 0xc0 | ((c >> 6) );
*buf++ = 0x80 | ((c >> 0) & 63); break;
case 0x00800:
case 0x00880: *buf++ = 0xe0 | ((c >> 12) );
*buf++ = 0x80 | ((c >> 6) & 63);
*buf++ = 0x80 | ((c >> 0) & 63); break;
default : *buf++ = 0xf0 | ((c >> 18) );
*buf++ = 0x80 | ((c >> 12) & 63);
*buf++ = 0x80 | ((c >> 6) & 63);
*buf++ = 0x80 | ((c >> 0) & 63);
}
}
*buf = 0;
argv[argc] = 0;
return argc;
}
static char **get_command_args(int *argc_ptr) {
static char *argv_buffer[CMDLINE_ARGV_MAX];
wchar_t *cmdline = GetCommandLineW();
*argc_ptr = cmdline_to_argv8(cmdline, argv_buffer);
return argv_buffer;
}

View File

@ -1,15 +0,0 @@
u64 __security_cookie;
void __security_init_cookie() {
// They say it's a random number so I generated
// one using numbergenerator.org
__security_cookie = 0xb26e04cc62ba48aULL;
}
void __security_check_cookie(u64 retrieved) {
if(__security_cookie != retrieved) {
// printf("Bro you've got a buffer overrun\n");
abort();
}
}

View File

@ -1,42 +0,0 @@
#pragma weak main
#pragma weak wmain
#pragma weak WinMain
int main(int argc, char** argv);
// int wmain(int argc, wchar_t** argv, wchar_t **envp);
// int WinMain(HINSTANCE inst, HINSTANCE pinst, LPSTR cmdline, int showcmd);
_Noreturn void mainCRTStartup() {
_setup_eh();
_setup_heap();
_setup_timer();
_io_init();
__security_init_cookie();
srand(0);
setlocale(LC_ALL, "C");
int argc;
char **args = get_command_args(&argc);
int exit_code = main(argc, args);
exit(exit_code);
}
/*_Noreturn void WinMainCRTStartup() {
_setup_eh();
_setup_heap();
_setup_timer();
_io_init();
__security_init_cookie();
srand(0);
setlocale(LC_ALL, "C");
HINSTANCE inst = GetModuleHandle(NULL);
LPSTR cmdline = GetCommandLineA();
int exit_code = WinMain(inst, 0, cmdline, SW_SHOWDEFAULT);
exit(exit_code);
}*/

View File

@ -1,138 +0,0 @@
// Windows symbols because windows
int _fltused=0;
#pragma comment(lib, "kernel32.lib")
// Exit routines
#define ATEXIT_FUNC_COUNT 64
#define ATQEXIT_FUNC_COUNT 64
static void (*atexit_funcs [ATEXIT_FUNC_COUNT])(void);
static void (*atqexit_funcs[ATQEXIT_FUNC_COUNT])(void);
static int atexit_func_count;
static int atqexit_func_count;
static char **get_command_args(int *argc_ptr);
_Noreturn void _Exit(int status) {
ExitProcess(status);
#if defined(_MSC_VER)
__assume(0);
#elif defined(__GNUC__)
__builtin_unreachable();
#endif
}
_Noreturn void quick_exit(int status) {
while(atqexit_func_count--) {
atqexit_funcs[atqexit_func_count]();
}
_Exit(status);
}
_Noreturn void exit(int status) {
while(atexit_func_count--) {
atexit_funcs[atqexit_func_count]();
}
_io_close();
_Exit(status);
}
_Noreturn void abort(void) {
raise(SIGABRT);
_Exit(-69);
}
int atexit(void (*func)(void)) {
if (atexit_func_count >= ATEXIT_FUNC_COUNT) {
return 0;
}
atexit_funcs[atexit_func_count++] = func;
return 1;
}
int at_quick_exit(void (*func)(void)) {
if(atqexit_func_count >= ATQEXIT_FUNC_COUNT) {
return 0;
}
atqexit_funcs[atqexit_func_count++] = func;
return 1;
}
char *getenv(const char *name) {
// The string pointed to shall not be modified by the program, but may be
// overwritten by a subsequent call to the getenv function
static size_t env_string_cap;
static char* env_string;
DWORD env_length = GetEnvironmentVariable(name, NULL, 0);
if (env_length == 0) {
return 0;
}
// Upscale the internal string
if (env_length > env_string_cap) {
char* newstr = realloc(env_string, env_length);
if (newstr == NULL) {
free(env_string);
return 0;
}
env_string = newstr;
env_string_cap = env_length;
}
GetEnvironmentVariable(name, env_string, env_length);
return env_string;
}
int system(const char* string) {
int wchars_required = MultiByteToWideChar(65001, 0, string, -1, NULL, 0);
wchar_t* cmd_line = malloc(sizeof(L"cmd.exe ") + (wchars_required * sizeof(wchar_t)));
if (cmd_line == NULL) {
goto error;
}
memcpy(cmd_line, L"cmd.exe ", sizeof(L"cmd.exe "));
MultiByteToWideChar(65001, 0, string, -1, cmd_line + sizeof("cmd.exe ") - 1, wchars_required);
STARTUPINFOW si = {
.cb = sizeof(STARTUPINFOW),
.dwFlags = STARTF_USESTDHANDLES,
.hStdInput = GetStdHandle(STD_INPUT_HANDLE),
.hStdError = GetStdHandle(STD_ERROR_HANDLE),
.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE)
};
PROCESS_INFORMATION pi = {0};
if (!CreateProcessW(NULL, cmd_line, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) {
goto error;
}
// Wait until child process exits.
WaitForSingleObject(pi.hProcess, INFINITE);
DWORD exit_code;
if (!GetExitCodeProcess(pi.hProcess, &exit_code)) {
goto error;
}
// Close process and thread handles.
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
free(cmd_line);
return exit_code;
error:
free(cmd_line);
return -1;
}
int _wcsicmp(wchar_t const* s1, wchar_t const* s2) {
int diff;
do {
diff = *s1 - *s2;
} while(diff != 0 && *s1 != 0 && *s2 != 0);
return diff;
}

View File

@ -1,628 +0,0 @@
enum FileMode {
MODE_INPUT,
MODE_OUTPUT,
MODE_UPDATE,
} typedef FileMode;
enum FileType {
FILE_BINARY,
FILE_TEXT,
} typedef FileType;
struct FileBuffer typedef FileBuffer;
struct FileBuffer {
int is_internal;
int mode;
size_t size;
void *data;
size_t written;
};
struct FILE {
HANDLE handle;
mbstate_t mbstate;
FileBuffer buffer;
FileMode io_mode;
FileType bt_mode;
int eof;
int err;
mtx_t lock;
bool temp;
char *temp_name;
FILE *prev;
FILE *next;
};
FILE *stdout;
FILE *stdin;
FILE *stderr;
// We hold a linked list of all file streams in order to flush all the buffers
// after the program terminates. It might be not a good idea to store all the
// files into this linked list, but for now performance is not a concern.
static FILE *_file_tracker = NULL;
static void _file_track(FILE *stream) {
if(_file_tracker != NULL) {
_file_tracker->next = stream;
stream->prev = _file_tracker;
stream->next = NULL;
_file_tracker = stream;
}
else {
_file_tracker = stream;
stream->prev = NULL;
stream->next = NULL;
}
}
static void _file_untrack(FILE *stream) {
FILE *prev = stream->prev;
FILE *next = stream->next;
if(prev != NULL) prev->next = next;
if(next != NULL) next->prev = prev;
if(next == NULL) _file_tracker = prev;
}
// Multithreaded access
static inline void _file_lock_init(FILE *stream) {
mtx_init(&stream->lock, mtx_plain);
}
static inline void _file_lock_destroy(FILE *stream) {
mtx_destroy(&stream->lock);
}
static inline void _file_lock(FILE *stream) {
mtx_lock(&stream->lock);
}
static inline void _file_unlock(FILE *stream) {
mtx_unlock(&stream->lock);
}
// Managing file handles
static inline FILE *_file_create(HANDLE handle, FileMode io_mode, FileType bt_mode) {
FILE *stream = calloc(1, sizeof(FILE));
if(stream == NULL) {
return NULL;
}
stream->handle = handle;
stream->io_mode = io_mode;
stream->bt_mode = bt_mode;
_file_lock_init(stream);
_file_track(stream);
return stream;
}
static inline void _file_close(FILE *stream) {
_file_lock(stream);
CloseHandle(stream->handle);
_file_untrack(stream);
_file_unlock(stream);
_file_lock_destroy(stream);
free(stream);
}
static void _io_init() {
HANDLE hstdout = GetStdHandle(STD_OUTPUT_HANDLE);
HANDLE hstderr = GetStdHandle(STD_ERROR_HANDLE);
HANDLE hstdin = GetStdHandle(STD_INPUT_HANDLE);
stdout = _file_create(hstdout, MODE_UPDATE, FILE_TEXT);
stderr = _file_create(hstderr, MODE_UPDATE, FILE_TEXT);
stdin = _file_create(hstdin, MODE_INPUT, FILE_BINARY);
char *in_buf = calloc(BUFSIZ, sizeof(char));
char *out_buf = calloc(BUFSIZ, sizeof(char));
stdin->buffer = (FileBuffer){1, _IOLBF, BUFSIZ, in_buf};
stdout->buffer = (FileBuffer){1, _IOLBF, BUFSIZ, out_buf};
stderr->buffer = (FileBuffer){1, _IONBF, 0, NULL};
SetConsoleCP(CP_UTF8); // Maybe it will work someday
SetConsoleOutputCP(CP_UTF8);
}
static void _io_close() {
while(_file_tracker != NULL) {
FILE *stream = _file_tracker;
fclose(stream);
_file_tracker = _file_tracker->next;
}
}
// File mode parsing
struct WindowsMode typedef WindowsMode;
struct WindowsMode {
DWORD access;
DWORD share;
DWORD disp;
};
static int _mode_parse(char const *mode, FileMode *pio_mode, FileType *pbt_mode, WindowsMode *win_mode) {
DWORD access = 0;
DWORD share = 0;
DWORD disp = 0;
FileMode io_mode = 0;
FileType bt_mode = 0;
int flag_p = 0;
int flag_b = 0;
int flag_x = 0;
switch(*mode++) {
case 'r': io_mode = MODE_INPUT; break;
case 'w': io_mode = MODE_OUTPUT; break;
case 'a': io_mode = MODE_UPDATE; break;
default: return 0;
}
while(*mode) switch(*mode++) {
case '+': flag_p = 1; break;
case 'b': flag_b = 1; break;
case 'x': flag_x = 1; break;
default: return 0;
}
bt_mode = flag_b? FILE_BINARY : FILE_TEXT;
switch(io_mode) {
case MODE_INPUT: {
access = GENERIC_READ | (flag_p? GENERIC_WRITE : 0);
share = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
disp = OPEN_EXISTING;
} break;
case MODE_OUTPUT: {
access = GENERIC_WRITE | (flag_p? GENERIC_READ : 0);
share = 0;
disp = CREATE_ALWAYS;
if(flag_x) {
disp = CREATE_NEW;
}
} break;
case MODE_UPDATE: {
access = GENERIC_READ | GENERIC_WRITE;
share = 0;
disp = OPEN_ALWAYS;
} break;
}
win_mode->access = access;
win_mode->share = share;
win_mode->disp = disp;
*pio_mode = io_mode;
*pbt_mode = bt_mode;
return 1;
}
// Operations on files
int remove(const char *filename) {
BOOL ok = DeleteFileA(filename);
return !ok;
}
int rename(const char *old, const char *new) {
BOOL ok = MoveFileA(old, new);
return !ok;
}
// Opening/closing files
char *tmpnam(char *s) {
static char internal_buffer[L_tmpnam];
char *buffer;
if(s != NULL) {
buffer = s;
}
else {
buffer = &internal_buffer[0];
}
UINT num = GetTempFileNameA(".", ".t_", 0, buffer);
if(num == 0) {
return NULL;
}
else {
return buffer;
}
}
FILE *tmpfile(void) {
char *file_name = malloc(L_tmpnam);
UINT num = GetTempFileNameA(".", ".t_", 0, &file_name[0]);
if(!num) {
return NULL;
}
FILE *tmp_file = fopen(&file_name[0], "wb+");
tmp_file->temp = true;
tmp_file->temp_name = file_name;
return tmp_file;
}
FILE *fopen(const char *restrict name, const char *restrict mode) {
WindowsMode win_mode;
DWORD flags = FILE_FLAG_WRITE_THROUGH;
FileMode io_mode;
FileType bt_mode;
if(!_mode_parse(mode, &io_mode, &bt_mode, &win_mode)) {
return NULL;
}
DWORD access = win_mode.access;
DWORD share = win_mode.share;
DWORD disp = win_mode.disp;
HANDLE handle = CreateFileA(name, access, share, NULL, disp, flags, NULL);
if(handle == INVALID_HANDLE_VALUE) {
return NULL;
}
FILE *stream = _file_create(handle, io_mode, bt_mode);
void *buffer_data = malloc(BUFSIZ);
stream->buffer = (FileBuffer) {1, _IOFBF, BUFSIZ, buffer_data};
return stream;
}
FILE *freopen(const char *restrict name, const char *restrict mode, FILE *restrict stream) {
if(stream == NULL) {
return NULL;
}
fflush(stream);
WindowsMode win_mode;
DWORD flags = FILE_FLAG_WRITE_THROUGH;
FileMode io_mode;
FileType bt_mode;
if(!_mode_parse(mode, &io_mode, &bt_mode, &win_mode)) {
return NULL;
}
DWORD access = win_mode.access;
DWORD share = win_mode.share;
DWORD disp = win_mode.disp;
if(name == NULL) {
// This codepath doesn't work
HANDLE handle = ReOpenFile(stream->handle, access, share, flags);
if(handle == INVALID_HANDLE_VALUE) {
return NULL;
}
}
else {
CloseHandle(stream->handle);
HANDLE handle = CreateFileA(name, access, share, NULL, disp, flags, NULL);
if(handle == INVALID_HANDLE_VALUE) {
return NULL;
}
*stream = (FILE) {0};
stream->handle = handle;
stream->io_mode = io_mode;
stream->bt_mode = bt_mode;
}
return stream;
}
int fclose(FILE *stream) {
if(fflush(stream) == EOF) {
return EOF;
}
if(stream->buffer.is_internal) {
free(stream->buffer.data);
}
if(!CloseHandle(stream->handle)) {
return EOF;
}
if(stream->temp) {
BOOL ok = DeleteFileA(stream->temp_name);
free(stream->temp_name);
if(!ok) {
return EOF;
}
}
_file_untrack(stream);
return 0;
}
// Buffering
int setvbuf(FILE *restrict stream, char *restrict ptr, int mode, size_t size) {
if(mode != _IOFBF && mode != _IOLBF && mode != _IONBF) {
return 1;
}
_file_lock(stream);
FileBuffer *buffer = &stream->buffer;
buffer->mode = mode;
if(ptr == NULL) {
buffer->data = realloc(buffer->data, size);
buffer->size = size;
}
else {
buffer->data = ptr;
buffer->size = size;
}
_file_unlock(stream);
return 0;
}
void setbuf(FILE *restrict stream, char *restrict buf) {
if(buf == NULL) {
setvbuf(stream, NULL, _IONBF, 0);
}
else {
setvbuf(stream, buf, _IOFBF, BUFSIZ);
}
}
int fflush(FILE *stream) {
_file_lock(stream);
int res = 0;
FileBuffer *buffer = &stream->buffer;
if(buffer->written != 0) {
size_t size = buffer->written;
void *data = buffer->data;
DWORD bytes_written;
BOOL ok = WriteFile(stream->handle, data, size, &bytes_written, NULL);
if(!ok) {
res = EOF;
stream->eof = 1;
}
buffer->written = 0;
}
_file_unlock(stream);
return res;
}
// Errors
int feof(FILE *stream) {
return stream->eof;
}
int ferror(FILE *stream) {
return stream->err;
}
void clearerr(FILE *stream) {
stream->eof = 0;
stream->err = 0;
}
void perror(char const *s) {
// printf("%s: %s\n", s, strerror(errno));
}
// File reads/writes
int fputc(int c, FILE *stream) {
_file_lock(stream);
FileBuffer *buffer = &stream->buffer;
int res = c;
if(buffer->mode == _IONBF) {
unsigned char str[1] = {c};
DWORD bytes_written;
BOOL ok = WriteFile(stream->handle, &str, 1, &bytes_written, NULL);
if(!ok) {
res = EOF;
stream->err = 1;
goto end;
}
}
else {
unsigned char *data = buffer->data;
data[buffer->written++] = (unsigned char)c;
int needs_flush;
needs_flush = (buffer->written == buffer->size);
if(buffer->mode == _IOLBF) {
needs_flush |= (c == '\n');
}
if(needs_flush) {
if(fflush(stream) == EOF) {
goto end;
}
}
}
end:
_file_unlock(stream);
return res;
}
int fgetc(FILE *stream) {
_file_lock(stream);
int res = 0;
FileBuffer *buffer = &stream->buffer;
int read_from_disk = 1;
if(buffer->mode != _IONBF) {
unsigned char *data = buffer->data;
if(buffer->written != 0) {
read_from_disk = 0;
res = data[--buffer->written];
}
}
if(read_from_disk) {
unsigned char buf[1];
DWORD bytes_read;
BOOL ok = ReadFile(stream->handle, buf, 1, &bytes_read, NULL);
if(bytes_read != 1) {
res = EOF;
stream->eof = 1;
goto end;
}
if(!ok) {
res = EOF;
goto end;
}
res = buf[0];
}
end:
_file_unlock(stream);
return res;
}
int ungetc(int c, FILE *stream) {
_file_lock(stream);
int res;
FileBuffer *buffer = &stream->buffer;
if(buffer->mode == _IONBF) {
res = EOF;
goto end;
}
else {
if(c == EOF) {
res = EOF;
goto end;
}
if(buffer->written == buffer->size) {
res = EOF;
goto end;
}
unsigned char *data = buffer->data;
data[buffer->written++] = (unsigned char)c;
res = c;
}
end:
_file_unlock(stream);
return res;
}
size_t fwrite(void const *restrict buffer, size_t size, size_t count, FILE *restrict stream) {
_file_lock(stream);
unsigned char const *bytes = (unsigned char const*)buffer;
size_t num_written;
for(num_written = 0; num_written < count; ++num_written) {
for(size_t bytes_written = 0; bytes_written < size; ++bytes_written) {
int ch = fputc(bytes[bytes_written], stream);
if(ch == EOF) {
goto end;
}
}
bytes += size;
}
end:
_file_unlock(stream);
return num_written;
}
size_t fread(void *restrict buffer, size_t size, size_t count, FILE *restrict stream) {
_file_lock(stream);
unsigned char *bytes = (unsigned char *)buffer;
size_t num_read;
for(num_read = 0; num_read < count; ++num_read) {
for(size_t bytes_read = 0; bytes_read < size; ++bytes_read) {
int ch = fgetc(stream);
if(ch == EOF) {
goto end;
}
bytes[bytes_read] = ch;
}
bytes += size;
}
end:
_file_unlock(stream);
return num_read;
}
int getchar(void) {
return fgetc(stdin);
}
int putchar(int ch) {
return fputc(ch, stdout);
}
char *fgets(char *restrict str, int count, FILE *restrict stream) {
if(count < 1) {
return str;
}
if(count == 1) {
str[0] = 0;
return str;
}
_file_lock(stream);
int i;
for(i = 0; i < count-1; ++i) {
int c = fgetc(stream);
if(c == EOF) {
stream->eof = 1;
if(i == 0) {
return NULL;
}
break;
}
str[i] = c;
if(c == '\n') {
++i;
break;
}
}
str[i] = 0;
_file_unlock(stream);
return str;
}
int fputs(char const *str, FILE *stream) {
_file_lock(stream);
int res = 0;
while(*str) {
int c = fputc(*str++, stream);
if(c == EOF) {
res = EOF;
break;
}
}
_file_unlock(stream);
return res;
}
int puts(char const *str) {
int res = fputs(str, stdout);
if(res == EOF) return EOF;
return putchar('\n');
}
char *gets(char *str) {
return fgets(str, 0x7fffffff, stdin);
}
// File positioning:
int fgetpos(FILE *restrict stream, fpos_t *restrict pos) {
LONG pos_hi = 0;
DWORD pos_lo = SetFilePointer(stream->handle, 0, &pos_hi, FILE_CURRENT);
if(pos_lo == INVALID_SET_FILE_POINTER) {
return 1;
}
int64_t offset = ((int64_t)pos_hi << 32) | (int64_t)pos_lo;
pos->offset = offset;
pos->mbstate.leftover = stream->mbstate.leftover;
pos->mbstate.high_surrogate = stream->mbstate.high_surrogate;
return 0;
}
int fseek(FILE *stream, long int offset, int whence) {
// Note(bumbread): the SEEK_SET, SEEK_CUR and SEEK_END are defined to match
// the Windows constants, so no conversion is requierd between them.
DWORD pos_lo = SetFilePointer(stream->handle, offset, NULL, whence);
if(pos_lo == INVALID_SET_FILE_POINTER) {
return -1L;
}
return 0;
}
int fsetpos(FILE *stream, const fpos_t *pos) {
LONG pos_lo = (LONG)(pos->offset & 0xffffffff);
DWORD status = SetFilePointer(stream->handle, pos_lo, NULL, FILE_BEGIN);
if(status == INVALID_SET_FILE_POINTER) {
return 1;
}
stream->mbstate.leftover = pos->mbstate.leftover;
stream->mbstate.high_surrogate = pos->mbstate.high_surrogate;
return 0;
}
long int ftell(FILE *stream) {
LONG pos_hi = 0;
DWORD pos_lo = SetFilePointer(stream->handle, 0, &pos_hi, FILE_CURRENT);
if(pos_lo == INVALID_SET_FILE_POINTER) {
return -1L;
}
int64_t offset = ((int64_t)pos_hi << 32) | (int64_t)pos_lo;
return offset;
}
void rewind(FILE *stream) {
fseek(stream, 0, SEEK_SET);
}

View File

@ -1,129 +0,0 @@
#define DEFAULT_ALIGNMENT 16
static HANDLE heap_handle;
static bool _is_power_of_two(size_t s) {
return (s & (s-1)) == 0;
}
static intptr_t _align_forward(intptr_t p, size_t a) {
return (p+a-1)&~(a-1);
}
static void _setup_heap() {
heap_handle = GetProcessHeap();
if (heap_handle == NULL) {
ExitProcess(-42069);
}
}
struct AllocationTag typedef AllocationTag;
struct AllocationTag {
void *ptr;
size_t size;
};
// Retrieve the tag using allocated pointer
static AllocationTag *_mem_block_tag(void *user_ptr) {
AllocationTag *tag = (void *)((char *)user_ptr - sizeof(AllocationTag));
return tag;
}
// Calculate the block size that is enough to hold user data, the tag, and
// the necessary free space in case the pointer from HeapAlloc needs further
// alignment
static size_t _mem_min_block_size(size_t alignment, size_t user_size) {
size_t size = user_size + sizeof(AllocationTag);
if(alignment > 8) {
size += alignment;
}
return size;
}
// Calculate the start of the user data, such that it's aligned, attach the tag
// to the allocated pointer
static void *_mem_block_setup(void *block_start, size_t block_size, size_t alignment) {
intptr_t block_start_i = (intptr_t)block_start;
intptr_t aligned_block_start_i = _align_forward(block_start_i, alignment);
intptr_t free_space = aligned_block_start_i - block_start_i;
if(free_space < sizeof(AllocationTag)) {
aligned_block_start_i += alignment;
}
AllocationTag *tag = _mem_block_tag(block_start);
tag->ptr = block_start;
tag->size = block_size;
return (void *)aligned_block_start_i;
}
void *_mem_alloc(size_t alignment, size_t size) {
// HeapAlloc is guaranteed to return 8-byte aligned pointer,
// so if our alignment is 8 or less we don't have to overallocate.
// otherwise we'll reserve extra `alignment` bytes to later adjust our
// memory buffer according to required alignment.
size_t block_size = _mem_min_block_size(alignment, size);
void *block_start = HeapAlloc(heap_handle, 0, block_size);
memset(block_start, 0, block_size);
if(block_start == NULL) {
return NULL;
}
return _mem_block_setup(block_start, block_size, alignment);
}
void *aligned_alloc(size_t alignment, size_t size) {
if(size == 0) {
return NULL;
}
if(alignment == 0) {
alignment = 8;
}
if(!_is_power_of_two(alignment)) {
return NULL;
}
return _mem_alloc(alignment, size);
}
void *calloc(size_t nmemb, size_t size) {
if(nmemb == 0 || size == 0) {
return NULL;
}
if(nmemb > SIZE_MAX/size) {
return NULL;
}
return _mem_alloc(DEFAULT_ALIGNMENT, nmemb * size);
}
void free(void *ptr) {
if(ptr == NULL) {
return;
}
AllocationTag *tag = (void *)((char *)ptr - sizeof(AllocationTag));
HeapFree(heap_handle, 0, tag->ptr);
}
void *malloc(size_t size) {
if(size == 0) {
return NULL;
}
return _mem_alloc(DEFAULT_ALIGNMENT, size);
}
void *realloc(void *ptr, size_t size) {
if (ptr == NULL) {
if (size == 0) {
return NULL;
}
return _mem_alloc(DEFAULT_ALIGNMENT, size);
} else if (size == 0) {
free(ptr);
return NULL;
} else {
AllocationTag *tag = _mem_block_tag(ptr);
void *old_block = tag->ptr;
size_t new_block_size = _mem_min_block_size(DEFAULT_ALIGNMENT, size);
void *new_block = HeapReAlloc(heap_handle, 0, old_block, new_block_size);
return _mem_block_setup(new_block, new_block_size, DEFAULT_ALIGNMENT);
}
}

View File

@ -1,85 +0,0 @@
#define _countof(arr) (sizeof (arr) / sizeof ((arr)[0]))
typedef struct SignalMapping {
DWORD code;
int signal;
} SignalMapping;
static SignalMapping map[] = {
{EXCEPTION_ACCESS_VIOLATION, SIGSEGV},
{EXCEPTION_IN_PAGE_ERROR, SIGSEGV},
{EXCEPTION_ARRAY_BOUNDS_EXCEEDED, SIGSEGV},
{EXCEPTION_DATATYPE_MISALIGNMENT, SIGALIGN},
{EXCEPTION_BREAKPOINT, SIGBREAK},
{EXCEPTION_FLT_DENORMAL_OPERAND, SIGFPE},
{EXCEPTION_FLT_DIVIDE_BY_ZERO, SIGFPE},
{EXCEPTION_FLT_INEXACT_RESULT, SIGFPE},
{EXCEPTION_FLT_INVALID_OPERATION, SIGFPE},
{EXCEPTION_FLT_OVERFLOW, SIGFPE},
{EXCEPTION_FLT_STACK_CHECK, SIGFPE},
{EXCEPTION_FLT_UNDERFLOW, SIGFPE},
{EXCEPTION_ILLEGAL_INSTRUCTION, SIGILL},
{EXCEPTION_INT_DIVIDE_BY_ZERO, SIGFPE},
{EXCEPTION_INT_OVERFLOW, SIGFPE},
{EXCEPTION_PRIV_INSTRUCTION, SIGILL},
{EXCEPTION_SINGLE_STEP, SIGSTEP},
};
static LONG _win32_handler(EXCEPTION_POINTERS *ExceptionInfo) {
EXCEPTION_RECORD *exception = ExceptionInfo->ExceptionRecord;
DWORD code = exception->ExceptionCode;
int signal = -1;
for(int mapping = 0; mapping != _countof(map); ++mapping) {
if(code == map[mapping].code) {
signal = map[mapping].signal;
}
}
if(signal != -1) {
raise(signal);
}
return EXCEPTION_CONTINUE_SEARCH;
}
static void _setup_eh() {
void *res = AddVectoredExceptionHandler(1, &_win32_handler);
if(res == NULL) {
ExitProcess(-69420);
}
}
void _signal_default_handler(int sig){}
void _signal_ignore_handler(int sig){}
static void (*(handlers[]))(int) = {
[SIGINT] = _signal_ignore_handler,
[SIGILL] = _signal_ignore_handler,
[SIGFPE] = _signal_ignore_handler,
[SIGSEGV] = _signal_ignore_handler,
[SIGTERM] = _signal_ignore_handler,
[SIGABRT] = _signal_ignore_handler,
[SIGBREAK] = _signal_ignore_handler,
[SIGALIGN] = _signal_ignore_handler,
[SIGSTEP] = _signal_ignore_handler,
};
void (*signal(int sig, void (*func)(int)))(int) {
if(_SIG_MIN <= sig && sig <= _SIG_MAX) {
handlers[sig] = func;
return func;
}
return SIG_ERR;
}
int raise(int sig)
{
if(_SIG_MIN <= sig && sig <= _SIG_MAX) {
handlers[sig](sig);
if(sig == SIGFPE || sig == SIGILL || sig == SIGSEGV) {
ExitProcess(-69420);
}
return 1;
}
return 0;
}

View File

@ -1,362 +0,0 @@
// Note(bumbread):
// https://gist.github.com/wbenny/6d7fc92e9b5c3194ce56bf8c60d6191d
#pragma comment(linker, "/merge:.CRT=.rdata")
#pragma section(".CRT$XLA", read)
__declspec(allocate(".CRT$XLA")) const PIMAGE_TLS_CALLBACK __xl_a = NULL;
#pragma section(".CRT$XLZ", read)
__declspec(allocate(".CRT$XLZ")) const PIMAGE_TLS_CALLBACK __xl_z = NULL;
#pragma section(".CRT$XLM", read)
__declspec(allocate(".CRT$XLM")) extern const PIMAGE_TLS_CALLBACK TlsCallbackArray;
char _tls_start = 0;
char _tls_end = 0;
unsigned int _tls_index = 0;
const IMAGE_TLS_DIRECTORY _tls_used = {
(ULONG_PTR)&_tls_start,
(ULONG_PTR)&_tls_end,
(ULONG_PTR)&_tls_index,
(ULONG_PTR)(&__xl_a + 1),
};
static void _thread_cleanup();
VOID NTAPI _tls_callback(
PVOID DllHandle,
DWORD Reason,
PVOID Reserved
)
{
switch(Reason) {
case DLL_THREAD_ATTACH: break;
case DLL_THREAD_DETACH: {
_thread_cleanup();
} break;
case DLL_PROCESS_ATTACH: break;
case DLL_PROCESS_DETACH: break;
}
// __debugbreak();
}
const PIMAGE_TLS_CALLBACK TlsCallbackArray = { &_tls_callback };
// NOTE: debug mutexes will follow the recursive logic but error if they
// actually recurse, this is slower than doing plain logic but it helps
// debug weird mutex errors.
//
// Based on these posts:
// https://preshing.com/20120305/implementing-a-recursive-mutex/
// https://preshing.com/20120226/roll-your-own-lightweight-mutex/
typedef struct UserClosure {
thrd_start_t func;
void* arg;
} UserClosure;
static DWORD _thread_call_user(void* arg) {
UserClosure info = *((UserClosure*) arg);
int result = info.func(info.arg);
free(arg);
return (DWORD) result;
}
thrd_t thrd_current(void) {
return (thrd_t){ GetCurrentThread() };
}
int thrd_create(thrd_t *thr, thrd_start_t func, void *arg) {
UserClosure* info = malloc(sizeof(UserClosure));
if (info == NULL) {
return thrd_nomem;
}
info->func = func;
info->arg = arg;
// technically thrd_start_t and LPTHREAD_START_ROUTINE aren't the same
// but are close enough to be ABI compatible, namely a difference in
// signedness of the return val.
thr->handle = CreateThread(NULL, 0, _thread_call_user, info, 0, NULL);
return thr->handle != NULL ? thrd_success : thrd_error;
}
int thrd_detach(thrd_t thr) {
return CloseHandle(thr.handle) != 0 ? thrd_success : thrd_error;
}
int thrd_equal(thrd_t thr0, thrd_t thr1) {
return GetThreadId(thr0.handle) == GetThreadId(thr1.handle);
}
int thrd_join(thrd_t thr, int *res) {
DWORD wait = WaitForSingleObject(thr.handle, INFINITE);
if (wait == WAIT_FAILED) {
return thrd_error;
} else if (wait == WAIT_TIMEOUT) {
return thrd_timedout;
}
if (res != NULL) {
// snatch that exit code
DWORD ures;
if (GetExitCodeThread(thr.handle, &ures) == 0) {
CloseHandle(thr.handle);
return thrd_error;
}
*res = (int) ures;
}
CloseHandle(thr.handle);
return thrd_success;
}
void thrd_yield(void) {
Sleep(0);
}
_Noreturn void thrd_exit(int res) {
_thread_cleanup();
ExitThread((DWORD)res);
__builtin_unreachable();
}
// TSS functions
#define TSS_KEYS_MAX 1088
static tss_dtor_t _tss_dtors[TSS_KEYS_MAX];
static bool _tss_init[TSS_KEYS_MAX];
static void _thread_cleanup() {
for(int i = 0; i != TSS_DTOR_ITERATIONS; ++i) {
for(unsigned k = 1; k != TSS_KEYS_MAX; ++k) {
if(!_tss_init[k]) {
continue;
}
void *data = TlsGetValue(k);
if(data == NULL) {
continue;
}
TlsSetValue(k, NULL);
if(_tss_dtors[k]) {
_tss_dtors[k](data);
}
}
}
}
int tss_create(tss_t *key, tss_dtor_t dtor) {
DWORD tls_index = TlsAlloc();
if(tls_index == TLS_OUT_OF_INDEXES) {
return thrd_error;
}
key->tls_index = tls_index;
if(tls_index >= TSS_KEYS_MAX) {
__debugbreak();
TlsFree(tls_index);
return thrd_error;
}
_tss_init[tls_index] = true;
_tss_dtors[tls_index] = dtor;
return thrd_success;
}
void tss_delete(tss_t key) {
_tss_init[key.tls_index] = false;
_tss_dtors[key.tls_index] = NULL;
TlsFree(key.tls_index);
}
void *tss_get(tss_t key) {
void *data = TlsGetValue(key.tls_index);
if(data == NULL && GetLastError() != ERROR_SUCCESS) {
return NULL;
}
return data;
}
int tss_set(tss_t key, void *val) {
if(!TlsSetValue(key.tls_index, val)) {
return thrd_error;
}
return thrd_success;
}
// Call once
static BOOL _call_once_trampoline(PINIT_ONCE init_once, PVOID param, PVOID *ctx) {
void (*user_func)(void) = param;
user_func();
return TRUE;
}
void call_once(once_flag *flag, void (*func)(void)) {
void *funcp = func;
InitOnceExecuteOnce((void *)flag, _call_once_trampoline, funcp, NULL);
}
// Condition variables
int cnd_init(cnd_t *cond) {
InitializeConditionVariable((void *)cond);
return thrd_success;
}
int cnd_broadcast(cnd_t *cond) {
WakeAllConditionVariable((void *)cond);
return thrd_success;
}
void cnd_destroy(cnd_t *cond) {
return; // Does nothing
}
int cnd_signal(cnd_t *cond) {
WakeConditionVariable((void *)cond);
return thrd_success;
}
int cnd_wait(cnd_t *cond, mtx_t *mtx) {
return thrd_error; // TODO after mutexes
}
int cnd_timedwait(cnd_t *restrict cond, mtx_t *restrict mtx, const struct timespec *restrict ts) {
return thrd_error; // TODO after mutexes
}
// Mutex functions
void mtx_destroy(mtx_t *mtx) {
CloseHandle(mtx->semaphore);
}
int mtx_init(mtx_t *mtx, int type) {
*mtx = (mtx_t){
.type = type,
.semaphore = CreateSemaphore(NULL, 0, 1, NULL)
};
if (type == mtx_timed) {
// TODO(NeGate): implement timed mutexes
return thrd_error;
}
return thrd_success;
}
int mtx_lock(mtx_t *mtx) {
bool try_recursive = (mtx->type == mtx_recursive);
#ifdef _DEBUG
try_recursive = true;
#endif
if (try_recursive) {
DWORD tid = GetCurrentThreadId();
if (atomic_fetch_add_explicit(&mtx->counter, 1, memory_order_acquire) > 1) {
if (tid != mtx->owner) {
WaitForSingleObject(mtx->semaphore, INFINITE);
} else {
// we recursive and already locked
#ifdef _DEBUG
if (mtx->type != mtx_recursive) {
return thrd_error;
}
#endif
}
}
mtx->owner = tid;
mtx->recursion++;
} else {
if (atomic_fetch_add_explicit(&mtx->counter, 1, memory_order_acquire) > 1) {
WaitForSingleObject(mtx->semaphore, INFINITE);
}
}
return thrd_success;
}
int mtx_timedlock(mtx_t *restrict mtx, const struct timespec *restrict ts) {
return thrd_error;
}
int mtx_trylock(mtx_t *mtx) {
bool try_recursive = (mtx->type == mtx_recursive);
#ifdef _DEBUG
try_recursive = true;
#endif
if (try_recursive) {
DWORD tid = GetCurrentThreadId();
// Do we own this mutex on this thread already?
if (mtx->owner == tid) {
#ifdef _DEBUG
if (mtx->type != mtx_recursive) {
return thrd_error;
}
#endif
atomic_fetch_add(&mtx->counter, 1);
} else {
int expected = 1;
if (!atomic_compare_exchange_strong(&mtx->counter, &expected, 0)) {
return thrd_busy;
}
mtx->owner = tid;
}
mtx->recursion++;
return thrd_success;
} else {
int expected = 1;
if (!atomic_compare_exchange_strong(&mtx->counter, &expected, 0)) {
return thrd_busy;
}
return thrd_success;
}
}
int mtx_unlock(mtx_t *mtx) {
bool try_recursive = (mtx->type == mtx_recursive);
#if _DEBUG
try_recursive = true;
#endif
if (try_recursive) {
DWORD tid = GetCurrentThreadId();
if (tid != mtx->owner) return thrd_error;
unsigned long recur = --mtx->recursion;
if (recur == 0) {
mtx->owner = 0;
}
if (atomic_fetch_sub_explicit(&mtx->counter, 1, memory_order_release) > 0) {
if (recur == 0) ReleaseSemaphore(mtx->semaphore, 1, NULL);
else {
#ifdef _DEBUG
if (mtx->type != mtx_recursive) {
return thrd_error;
}
#endif
}
}
} else {
// release?
if (atomic_fetch_sub_explicit(&mtx->counter, 1, memory_order_release) > 0) {
ReleaseSemaphore(mtx->semaphore, 1, NULL);
}
}
return thrd_success;
}

View File

@ -1,439 +0,0 @@
#define NS_PER_SEC 1000000000
#define NS_PER_MS 1000000
#define TIME_TICKS_PER_SEC 1000000000ULL
#define FT_TICKS_BEFORE_UNIX_EPOCH 116444736000000000ULL
typedef struct tm tm_t;
// Store the time since we started running the process
static uint64_t timer_freq;
static uint64_t timer_start;
// Initialize timers
static void _setup_timer(void) {
LARGE_INTEGER freq, start;
QueryPerformanceFrequency(&freq);
QueryPerformanceCounter(&start);
timer_start = start.QuadPart;
timer_freq = freq.QuadPart;
}
// Timestamp utilitity functions
static ULONGLONG _time_filetime_to_ns(FILETIME ft) {
ULARGE_INTEGER ft64 = {
.LowPart = ft.dwLowDateTime,
.HighPart = ft.dwHighDateTime,
};
ULONGLONG fticks = ft64.QuadPart;
return fticks * 100;
}
static ULONGLONG _time_utc_ns() {
FILETIME ft;
GetSystemTimeAsFileTime(&ft);
ULONGLONG ticks = _time_filetime_to_ns(ft);
ULONGLONG unix_ns = (ticks - FT_TICKS_BEFORE_UNIX_EPOCH*100);
return unix_ns;
}
static ULONGLONG _time_mono_ns() {
ULONGLONG time_ms = GetTickCount64();
ULONGLONG time_ns = time_ms * NS_PER_MS;
return time_ns;
}
static ULONGLONG _time_process_ns() {
FILETIME _1;
FILETIME _2;
FILETIME ktime;
FILETIME utime;
HANDLE current_process = GetCurrentProcess();
if(GetProcessTimes(current_process, &_1, &_2, &ktime, &utime) == 0) {
abort();
}
ULONGLONG kernel_time = _time_filetime_to_ns(ktime);
ULONGLONG user_time = _time_filetime_to_ns(utime);
ULONGLONG cpu_time = kernel_time + user_time;
return cpu_time;
}
static ULONGLONG _time_thread_ns() {
FILETIME _1;
FILETIME _2;
FILETIME ktime;
FILETIME utime;
HANDLE current_thread = GetCurrentThread();
if(GetThreadTimes(current_thread, &_1, &_2, &ktime, &utime) == 0) {
abort();
}
ULONGLONG kernel_time = _time_filetime_to_ns(ktime);
ULONGLONG user_time = _time_filetime_to_ns(utime);
ULONGLONG cpu_time = kernel_time + user_time;
return cpu_time;
}
// Timer functions
clock_t clock(void) {
LARGE_INTEGER curr;
if (!QueryPerformanceCounter(&curr)) {
return -1;
}
if (curr.QuadPart < timer_start) {
return -1;
}
clock_t ticks = curr.QuadPart - timer_start;
// Same as (ticks / timer_freq * CLOCKS_PER_SEC) but more precise
return ticks / timer_freq * CLOCKS_PER_SEC
+ ticks % timer_freq * CLOCKS_PER_SEC / timer_freq;
}
time_t time(time_t *timer) {
ULONGLONG unix_nanos = _time_utc_ns();
time_t timer_ticks = unix_nanos;
if(timer != NULL) {
*timer = timer_ticks;
}
return timer_ticks;
}
double difftime(time_t time1, time_t time0) {
double resolution = (double)TIME_TICKS_PER_SEC;
if(time1 >= time0) return (double)(time1 - time0) / resolution;
else return -(double)(time0 - time1) / resolution;
}
int timespec_get(struct timespec *ts, int base) {
ULONGLONG current_ns;
switch(base) {
case TIME_UTC: current_ns = _time_utc_ns(); break;
case TIME_MONOTONIC: current_ns = _time_mono_ns(); break;
case TIME_ACTIVE: current_ns = _time_process_ns(); break;
case TIME_THREAD_ACTIVE: current_ns = _time_thread_ns(); break;
default: return 0;
}
ts->tv_sec = current_ns / NS_PER_SEC;
ts->tv_nsec = current_ns;
return base;
}
int timespec_getres(struct timespec *ts, int base) {
switch(base) {
case TIME_UTC: return NS_PER_SEC;
case TIME_MONOTONIC: return NS_PER_SEC;
case TIME_ACTIVE: return NS_PER_SEC;
case TIME_THREAD_ACTIVE: return NS_PER_SEC;
default: return 0;
}
}
// Human-readable time
const int _days_in_month[12] = {
31,28, 31,30,31, 30,31,31, 30,31,30, 31
};
const int _month_days_since_year_start[12] = {
0,
31,
31+28,
31+28+31,
31+28+31+30,
31+28+31+30+31,
31+28+31+30+31+30,
31+28+31+30+31+30+31,
31+28+31+30+31+30+31+31,
31+28+31+30+31+30+31+31+30,
31+28+31+30+31+30+31+31+30+31,
31+28+31+30+31+30+31+31+30+31+30,
};
static bool _is_leap_year(int year) {
if(year % 400 == 0) {
return true;
}
if(year % 100 == 0) {
return false;
}
if(year % 4 == 0) {
return true;
}
return false;
}
static int _leap_years_before(int year) {
year--;
return (year / 4) - (year / 100) + (year / 400);
}
static int _leap_years_between(int start, int end) {
return _leap_years_before(end) - _leap_years_before(start + 1);
}
static int _whole_days_since_year_start(int year, int mon, int day) {
int days = _month_days_since_year_start[mon] + day;
if(mon > 1 || (mon == 1 && day > 27)) {
if(_is_leap_year(year)) {
days += 1;
}
}
return days;
}
static void _tm_adjust(tm_t *time) {
long long year = 1900 + time->tm_year;
long long mon = time->tm_mon;
long long day = time->tm_mday - 1;
long long hour = time->tm_hour;
long long min = time->tm_min;
long long sec = time->tm_sec;
// Adjust
if(sec < 0) {
min -= (-sec+59)/60;
sec = (sec%60 + 60) % 60;
}
else if(sec >= 60) {
min += sec / 60;
sec %= 60;
}
if(min < 0) {
hour -= (-min+59)/60;
min = (min%60 + 60) % 60;
}
else if(min >= 60) {
hour += min / 60;
min %= 60;
}
if(hour < 0) {
day -= (-hour+23)/24;
hour = (hour%24 + 24) % 24;
}
else if(hour >= 24) {
day += hour / 24;
hour %= 24;
}
if(mon < 0) {
year -= (-mon+11)/12;
mon = (mon%12+12)%12;
}
else if(mon >= 12) {
year += mon / 12;
mon %= 12;
}
if(day < 0) {
for(;;) {
int mon_prev = mon - 1;
int year_prev = year;
if(mon_prev == -1) {
mon_prev = 11;
year_prev -= 1;
}
int days_in_prev_month = _days_in_month[mon_prev];
if(mon_prev == 1 && _is_leap_year(year_prev)) {
days_in_prev_month += 1;
}
if(-day > days_in_prev_month) {
day += days_in_prev_month;
mon -= 1;
if(mon == -1) {
mon = 11;
year -= 1;
}
}
else {
break; // Can't subtract any whole months, exit the loop
}
}
if(day < 0) {
mon -= 1;
day = _days_in_month[mon] + day;
if(mon == -1) {
mon = 11;
year -= 1;
}
}
}
else {
for(;;) {
int days_in_month = _days_in_month[mon];
if(mon == 1 && _is_leap_year(year)) {
days_in_month += 1;
}
if(day < days_in_month) {
break;
}
day -= days_in_month;
mon += 1;
}
}
// Refill the struct with normalized time
time->tm_year = year - 1900;
time->tm_mon = mon;
time->tm_mday = day + 1;
time->tm_hour = hour;
time->tm_min = min;
time->tm_sec = sec;
}
time_t mktime(tm_t *time) {
// Get the human-readable time from the structure
_tm_adjust(time);
long long year = 1900 + time->tm_year;
long long mon = time->tm_mon;
long long day = time->tm_mday - 1;
long long hour = time->tm_hour;
long long min = time->tm_min;
long long sec = time->tm_sec;
if(year < 1970) {
return (time_t)(-1);
}
// Calculate unix timestamp
time_t timestamp;
timestamp = (year - 1970) * 365 + _leap_years_between(1970, year);
time_t days_since_year = _whole_days_since_year_start(year, mon, day);
timestamp = timestamp + days_since_year;
time_t days_since_epoch = timestamp;
timestamp = timestamp * 24 + hour;
timestamp = timestamp * 60 + min;
timestamp = timestamp * 60 + sec;
timestamp = timestamp * NS_PER_SEC;
// Refill the week day and year day
time->tm_wday = (days_since_epoch % 7 + 4) % 7; // 1970-01-01 is thursday (wday=4)
time->tm_yday = days_since_year;
time->tm_isdst = -1;
return timestamp;
}
// Breaking-down of the time
tm_t *gmtime(const time_t *timer) {
tm_t *time = malloc(sizeof(tm_t));
time_t timestamp = *timer;
timestamp /= NS_PER_SEC;
time->tm_sec = timestamp % 60;
timestamp /= 60;
time->tm_min = timestamp % 60;
timestamp /= 60;
time->tm_hour = timestamp % 24;
timestamp /= 24;
int year = 1970;
int days = timestamp;
int days_since_epoch = days;
// Start subtracting 400,100,4-year-stretches
const int DAYS_IN_400_YEARS = 365 * 400 + 97;
const int DAYS_IN_100_YEARS = 365 * 100 + 24;
const int DAYS_IN_4_YEARS = 365 * 4 + 1;
year += (days / DAYS_IN_400_YEARS) * 400;
days %= DAYS_IN_400_YEARS;
year += (days / DAYS_IN_100_YEARS) * 100;
days %= DAYS_IN_100_YEARS;
year += (days / DAYS_IN_4_YEARS) * 4;
days %= DAYS_IN_4_YEARS;
// Count remaining up-to 3 years in a loop
for(;;) {
int this_year_days = 365 + _is_leap_year(year);
if(days < this_year_days) {
break;
}
year += 1;
days -= this_year_days;
}
// Find the current month
int days_since_year = days;
int month = 0;
for(;;) {
int days_in_month = _days_in_month[month] + _is_leap_year(year);
if(days < days_in_month) {
break;
}
days -= days_in_month;
month += 1;
}
time->tm_year = year - 1900;
time->tm_mon = month;
time->tm_mday = days + 1;
time->tm_wday = (days_since_epoch % 7 + 4) % 7; // 1970-01-01 is thursday (wday=4)
time->tm_yday = days_since_year;
time->tm_isdst = -1;
return time;
}
static bool _offset_utc_time_to_local(tm_t *time) {
TIME_ZONE_INFORMATION tz;
if(GetTimeZoneInformation(&tz) == TIME_ZONE_ID_INVALID) {
return false;
}
int bias = tz.Bias;
time->tm_min -= bias;
mktime(time);
return true;
}
tm_t *localtime(const time_t *timer) {
tm_t *utc_time = gmtime(timer);
if(!_offset_utc_time_to_local(utc_time)) {
return NULL;
}
return utc_time;
}
// String formatting
static void _time_str_print2(char *str, int v) {
char hi = (v/10)%10 + '0';
char lo = v%10 + '0';
str[0] = hi;
str[1] = lo;
}
static void _time_str_print4(char *str, int v) {
char c1 = (v/1000)%10 + '0';
char c2 = (v/100)%10 + '0';
char c3 = (v/10)%10 + '0';
char c4 = v%10 + '0';
str[0] = c1;
str[1] = c2;
str[2] = c3;
str[3] = c4;
}
char *asctime(const struct tm *time) {
static const char wday_name[7][5] = {
"Sun ", "Mon ", "Tue ", "Wed ", "Thu ", "Fri ", "Sat ",
};
static const char mon_name[12][5] = {
"Jan ", "Feb ", "Mar ", "Apr ", "May ", "Jun ",
"Jul ", "Aug ", "Sep ", "Oct ", "Nov ", "Dec ",
};
char *buf = calloc(1, 26);
if(buf == NULL) {
return NULL;
}
strcpy(buf, wday_name[time->tm_wday]);
strcat(buf, mon_name[time->tm_mon]);
char *str = buf+8;
_time_str_print2(str+0, time->tm_mday);
_time_str_print2(str+3, time->tm_hour);
_time_str_print2(str+6, time->tm_min);
_time_str_print2(str+9, time->tm_sec);
str[2] = ' ';
str[5] = ':';
str[8] = ':';
str[11] = ' ';
_time_str_print4(str+12, 1900+time->tm_year);
str[16] = '\n';
str[17] = 0;
return buf;
}
char *ctime(const time_t *timer) {
return asctime(localtime(timer));
}
size_t strftime(char *restrict s, size_t size, const char *restrict fmt, const tm_t *restrict time) {
return 0;
}

View File

@ -1,13 +0,0 @@
#pragma once
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <processenv.h>
#include <DbgHelp.h>
#include <winternl.h>
static void _setup_timer(void);
static void _setup_eh();
static void _setup_heap();
static void _io_close();

View File

@ -1,82 +0,0 @@
int abs(int n) {
if(n < 0) return -n;
return n;
}
long absl(long n) {
if(n < 0) return -n;
return n;
}
long long absll(long long n) {
if(n < 0) return -n;
return n;
}
div_t div(int x, int y) {
div_t res;
res.quot = x / y;
res.rem = x % y;
return res;
}
ldiv_t ldiv(long x, long y) {
ldiv_t res;
res.quot = x / y;
res.rem = x % y;
return res;
}
lldiv_t lldiv(long long x, long long y) {
lldiv_t res;
res.quot = x / y;
res.rem = x % y;
return res;
}
const void *bsearch(
const void *key,
const void *base,
size_t nmemb,
size_t size,
int (*compar)(const void *, const void *)
) {
size_t left = 0;
size_t right = nmemb;
const char* buffer = base;
while (left < right) {
size_t middle = (left + right) / 2;
int cmp = compar(&buffer[middle * size], key);
if (cmp == 0) return &buffer[left * size];
if (cmp < 0) left = middle + 1;
else right = middle;
}
return NULL;
}
void qsort(
void *base,
size_t nmemb,
size_t size,
int (*diff)(const void *, const void *)
) {
// Ima be doing bublbe sort for now
char *bytes = base;
for(size_t i = 0; i != nmemb-1; ++i) {
for(size_t j = 0; j < nmemb-i-1; ++j) {
char *this = bytes+j*size;
char *that = this+size;
if(diff(this, that) > 0) {
for(size_t b=0;b!=size;++b) {
char temp = this[b];
this[b] = that[b];
that[b] = temp;
}
}
}
}
}

View File

@ -1,21 +0,0 @@
int mblen(const char *s, size_t n) {
return mbtowc((wchar_t*)0, s, n);
}
int mbtowc(wchar_t *restrict pwc, const char *restrict s, size_t n) {
return 0;
}
size_t mbstowcs(wchar_t *restrict pwcs, const char *restrict s, size_t n) {
return 0;
}
int wctomb(char *s, wchar_t wchar) {
return 0;
}
size_t wcstombs(char *restrict s, const wchar_t *restrict pwcs, size_t n) {
return 0;
}

View File

@ -1,15 +0,0 @@
// TODO: the code for rand/srand was shamelessly copied
// from C11 standard's example and is a simple LCG.
// gotta implement a better random function, or no idc
static int last_random_number;
int rand(void) {
last_random_number = last_random_number * 1103515245 + 12345;
return (unsigned int)(last_random_number/65536) % RAND_MAX;
}
void srand(unsigned int seed) {
last_random_number = seed;
}

View File

@ -1,243 +0,0 @@
void *memcpy(void *restrict to, void const *restrict from, size_t n) {
u8 *restrict dst = to;
u8 const *restrict src = from;
while (n--) {
*dst++ = *src++;
}
return dst;
}
void *memmove(void *to, const void *from, size_t n) {
u8 *dst = to;
u8 const *src = from;
if (src != dst) {
if (src < dst) {
// reverse copy
for (size_t i = n; i--;) dst[i] = src[i];
} else {
// normal copy
for (size_t i = 0; i < n; i++) dst[i] = src[i];
}
}
return dst;
}
char *strcpy(char *restrict dst, char const *restrict src) {
size_t i = 0;
for(i = 0; src[i]; ++i) {
dst[i] = src[i];
}
dst[i] = 0;
return dst;
}
char *strncpy(char *restrict dst, char const *restrict src, size_t n) {
size_t i;
for(i = 0; i != n && src[i]; ++i) {
dst[i] = src[i];
}
for(; i != n; ++i) {
dst[i] = 0;
}
return dst;
}
char *strcat(char *restrict dst, const char *restrict src) {
size_t start = strlen(dst);
return strcpy(dst+start, src);
}
char *strncat(char *restrict dst, char const *restrict src, size_t n) {
size_t start = strlen(dst);
strncpy(dst+start, src, n);
return dst;
}
int memcmp(void const *p1, void const *p2, size_t n) {
u8 const *s1 = p1;
u8 const *s2 = p2;
size_t i;
for(i = 0; i != n; ++i) {
if(s1[i] != s2[i]) break;
}
if(i != n) {
if(s1[i] < s2[i]) return -1;
if(s1[i] > s2[i]) return 1;
}
return 0;
}
void *memset(void *s, int c, size_t n) {
u8 *restrict buf = s;
while (n--) {
*buf++ = c;
}
return s;
}
int strcmp(char const *s1, char const *s2) {
size_t i;
for(i = 0; s1[i] && s2[i]; ++i) {
if(s1[i] != s2[i]) break;
}
if(s1[i] < s2[i]) return -1;
if(s1[i] > s2[i]) return +1;
return 0;
}
int strncmp(const char *s1, const char *s2, size_t n) {
size_t i;
for(i = 0; i != n && s1[i] && s2[i]; ++i) {
if(s1[i] != s2[i]) break;
}
if(s1[i] < s2[i]) return -1;
if(s1[i] > s2[i]) return +1;
return 0;
}
int strcoll(const char *s1, const char *s2) {
return strcmp(s1, s2);
}
// TODO: I don't quite understand the intent nor use behind this function
// so I'm just going to ignore locales for now.
size_t strxfrm(char *restrict s1, const char *restrict s2, size_t n) {
size_t len = strlen(s2);
if(s1 != NULL && n != 0) {
for(size_t i = 0; i != n; ++i) {
*s1 = *s2;
}
}
return len;
}
void *memchr(const void *ptr, int c, size_t n) {
const char *s = ptr;
for(size_t i = 0; i != n; ++i) {
if(s[i] == c) {
// Casting away const because clang warnings
return (void *)(s+i);
}
}
return NULL;
}
char *strchr(const char *s, int c) {
do {
if(*s == c) return (char *)s;
} while(*s++);
return NULL;
}
size_t strspn(const char *s1, const char *s2) {
size_t i = 0;
for(; *s1; ++s1) {
if(strchr(s2, *s1) == NULL) {
break;
}
++i;
}
return i;
}
size_t strcspn(const char *s1, const char *s2) {
size_t i = 0;
for(; *s1; ++s1) {
if(strchr(s2, *s1) != NULL) {
break;
}
++i;
}
return i;
}
char *strpbrk(const char *s1, const char *s2) {
while(*s1) {
if(strchr(s2, *s1) == NULL) {
break;
}
++s1;
}
return (char *)s1;
}
char *strrchr(const char *s, int c) {
char const *last = NULL;
for(; *s != 0; ++s) {
if(*s == c) last = s;
}
return (char *)last;
}
char *strstr(const char *s1, const char *s2) {
if(*s2 == 0) return (char *)s1;
size_t len = strlen(s2);
for(; *s1 != 0; ++s1) {
if(strncmp(s1, s2, len) == 0) return (char *)s1;
}
return NULL;
}
// TODO: there may be restrict-related UB
char *strtok(char *restrict s1, const char *restrict s2) {
static char *str;
return strtok_r(s1, s2, &str);
}
char *strtok_r(char *restrict s1, const char *restrict s2, char **restrict ctx) {
if(s1 != NULL) *ctx = s1;
if(*ctx == NULL) return NULL;
size_t junk_len = strspn(*ctx, s2);
char *tok_start = *ctx + junk_len;
if(*tok_start == 0) {
*ctx = NULL;
return NULL;
}
size_t tok_len = strcspn(*ctx, s2);
char *tok_end = tok_start + tok_len;
*tok_end = 0;
*ctx = tok_end+1;
return tok_start;
}
char *strerror(int errnum) {
switch(errnum) {
case 0: return "No errors";
case EDOM: return "Value is outside of domain of the function";
case EILSEQ: return "Illegal byte sequence";
case ERANGE: return "Value is out of range";
}
return "Unkown error";
}
size_t strlen(const char *s) {
size_t i = 0;
while (s[i]) {
i++;
}
return i;
}
size_t strnlen_s(const char *s, size_t maxsize) {
if (s == NULL) return 0;
size_t i = 0;
while (s[i] && i < maxsize) {
i++;
}
return i;
}
char *strdup(const char *str1) {
if(str1 == NULL) return NULL;
size_t len = strlen(str1);
char *copy = calloc(len+1, 1);
strcpy(copy, str1);
return copy;
}

View File

@ -1,126 +0,0 @@
// size_t mbrtoc16(
// char16_t *restrict pc16,
// char const *restrict s,
// size_t n,
// mbstate_t *restrict ps
// ) {
// // Figure out the conversion state
// static mbstate_t static_mbstate = {0};
// if(ps == NULL) ps = &static_mbstate;
// if(s == NULL) {
// *ps = (mbstate_t) {0xd800};
// return 0;
// }
// // Check leftovers, using 0xd800 as "no leftover" marker because it
// // doesn't encode a valid character.
// if(ps->leftover == 0xd800) {
// // Decode the UTF-8 encoded codepoint
// char32_t code_point;
// int mblen = utf8_chdec((char8_t *)s, n, &code_point);
// if(mblen == UNI_ESTRLN) return (size_t)(-2);
// if(mblen <= 0) goto invalid_seq;
// // Encode the codepoint into UTF-16 string
// char16_t str[2];
// int c16len = utf16_chenc(str, 2, code_point);
// if(c16len <= 0) goto invalid_seq;
// // Assign the decoded UTF-16 character, decide leftover
// if(pc16 != NULL) *pc16 = str[0];
// ps->leftover = (c16len == 2? str[1] : 0xd800);
// return (size_t)mblen;
// }
// else {
// // Otherwise use and reset the leftover
// if(pc16 != NULL) *pc16 = ps->leftover;
// ps->leftover = 0xd800;
// return (size_t)(-3);
// }
// invalid_seq:
// errno = EILSEQ;
// return (size_t)(-1);
// }
// size_t c16rtomb(
// char *restrict s,
// char16_t c16,
// mbstate_t *restrict ps
// ) {
// // Figure out conversion state
// static mbstate_t static_mbstate = {0};
// if(ps == NULL) ps = &static_mbstate;
// if(s == NULL) {
// *ps = (mbstate_t) {0xd800};
// return 0;
// }
// char32_t codepoint_to_write;
// // Check whether a high surrogate was detected in a previous call to the
// // function. If not, the high_surrogate value is 0xd800
// if(ps->high_surrogate == 0xd800) {
// // If c16 is a surrogate record it, or throw an error
// if(uni_is_hsur(c16)) {
// ps->high_surrogate = c16;
// return 0;
// }
// else if(uni_is_lsur(c16)) {
// goto invalid_char;
// }
// // We'll just write c16
// codepoint_to_write = c16;
// }
// // If high surrogate exists, the next character must be a low surrogate
// // so we'll write a codepoint made out of high and low surrogates
// else if(uni_is_lsur(c16)) {
// codepoint_to_write = uni_surtoc(ps->high_surrogate, c16);
// }
// else goto invalid_char;
// // Write the codepoint that we decided to write to multibyte string
// int written_len = utf8_chenc((char8_t *)s, 4, codepoint_to_write);
// if(written_len < 0) {
// goto invalid_char;
// }
// s[written_len] = 0;
// return (size_t)written_len;
// invalid_char:
// errno = EILSEQ;
// return (size_t)(-1);
// }
// size_t mbrtoc32(
// char32_t *restrict pc32,
// char const *restrict s,
// size_t n,
// mbstate_t *restrict ps
// ) {
// if(s == NULL) {
// return 0;
// }
// char32_t code_point;
// int mblen = utf8_chdec((char8_t *)s, n, &code_point);
// if(mblen == UNI_ESTRLN) return (size_t)(-2);
// if(mblen <= 0) {
// errno = EILSEQ;
// return (size_t)(-1);
// }
// *pc32 = code_point;
// if(code_point == 0) return 0;
// return (size_t)mblen;
// }
// size_t c32rtomb(
// char *restrict s,
// char32_t c32,
// mbstate_t *restrict ps
// ) {
// if(s == NULL) {
// *ps = (mbstate_t) {0};
// return 0;
// }
// int mblen = utf8_chenc((char8_t *)s, 4, c32);
// if(mblen <= 0) {
// errno = EILSEQ;
// return (size_t)(-1);
// }
// return (size_t)mblen;
// }

View File

@ -1,76 +0,0 @@
// Some of these more horizontal screen space than I consider healthy, that's
// why I define shorter versions for some of the types. long integers are
// special offenders
// The other part of this file are the convenience macros that could be used
// mostly anywhere in the ciabatta implementation.
typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;
typedef int8_t i8;
typedef int16_t i16;
typedef int32_t i32;
typedef int64_t i64;
typedef int_least8_t li8;
typedef int_least16_t li16;
typedef int_least32_t li32;
typedef int_least64_t li64;
typedef int_fast8_t fi8;
typedef int_fast16_t fi16;
typedef int_fast32_t fi32;
typedef int_fast64_t fi64;
typedef long int intl;
typedef long long int intll;
typedef unsigned int intu;
typedef unsigned long int intul;
typedef unsigned long long int intull;
typedef float f32;
typedef double f64;
typedef long double fl64;
typedef wchar_t wchar;
#define IN_RANGE(start, v, end) ((start) <= (v) && (v) <= (end))
#define CONCAT(a,b) a ## b
#define STR_(a) #a
#define STR(a) STR_(a)
#define F64_BITS(x) ((union {f64 f; u64 i;}){.f=x}).i
#define F64_CONS(x) ((union {f64 f; u64 i;}){.i=x}).f
#define F32_BITS(x) ((union {f32 f; u32 i;}){.f=x}).i
#define F32_CONS(x) ((union {f32 f; u32 i;}){.i=x}).f
#define F64_MANT_MASK UINT64_C(0xfffffffffffff)
#define F64_MANT_MAX UINT64_C(0xfffffffffffff)
#define F64_MANT_BITS 52
#define F64_BEXP_BITS 11
#define F64_BEXP_MASK 0x7ff
#define F64_BEXP_MAX 0x7ff
#define F32_MANT_MASK 0x7fffff
#define F32_MANT_MAX 0x7fffff
#define F32_MANT_BITS 23
#define F32_BEXP_BITS 8
#define F32_BEXP_MASK 0xff
#define F32_BEXP_MAX 0xff
#define F64_SIGN(bits) (bits >> (F64_MANT_BITS + F64_BEXP_BITS))
#define F64_BEXP(bits) ((bits >> F64_MANT_BITS) & F64_BEXP_MASK)
#define F64_MANT(bits) ((bits) & F64_MANT_MASK)
#define F32_SIGN(bits) (bits >> (F32_MANT_BITS + F32_BEXP_BITS))
#define F32_BEXP(bits) ((bits >> F32_MANT_BITS) & F32_BEXP_MASK)
#define F32_MANT(bits) ((bits) & F32_MANT_MASK)
#define MIN(a,b) ((a)<(b)?(a):(b))
#define MAX(a,b) ((a)>(b)?(a):(b))

View File

@ -1,99 +0,0 @@
size_t wcslen(const wchar_t *s) {
size_t len = 0;
while(s[len++]);
return len;
}
wchar_t *wmemset(wchar_t *str, wchar_t c, size_t n) {
while(n--) {
str[n] = c;
}
return str;
}
wchar_t *wmemmove(wchar_t *dst, wchar_t const *src, size_t n) {
if(dst != src) {
if(dst < src) {
for (size_t i = n; i--;) dst[i] = src[i];
} else {
for (size_t i = 0; i < n; i++) dst[i] = src[i];
}
}
return dst;
}
wchar_t *wmemcpy(wchar_t *restrict dst, wchar_t const *restrict src, size_t n) {
while(n--) dst[n] = src[n];
return (wchar_t *)dst;
}
wchar_t *wcscpy(wchar_t *restrict dst, wchar_t const *restrict src) {
size_t i;
for(i = 0; src[i]; ++i) {
dst[i] = src[i];
}
dst[i] = 0;
return (wchar_t *)dst;
}
wchar_t *wcsncpy(wchar_t *restrict dst, wchar_t const *restrict src, size_t n) {
// TODO: more than one null terminator, not write if n was reached
size_t i;
for(i = 0; i != n && src[i]; ++i) {
dst[i] = src[i];
}
dst[i] = 0;
return (wchar_t *)dst;
}
wchar_t *wcscat(wchar_t *restrict dst, wchar_t const *restrict src) {
size_t dst_len = wcslen(dst);
size_t i;
for(i = 0; src[i]; ++i) {
dst[dst_len + i] = src[i];
}
dst[dst_len + i] = 0;
return (wchar_t *)dst;
}
wchar_t *wcsncat(wchar_t *restrict dst, wchar_t const *restrict src, size_t n) {
size_t dst_len = wcslen(dst);
size_t i;
for(i = 0; i != n && src[i]; ++i) {
dst[dst_len + i] = src[i];
}
dst[dst_len + i] = 0;
return (wchar_t *)dst;
}
int wcscmp(wchar_t const *s1, wchar_t const *s2) {
size_t i;
for(i = 0; s1[i] && s2[i]; ++i) {
if(s1[i] != s2[i]) break;
}
if(s1[i] < s2[i]) return -1;
if(s1[i] > s2[i]) return 1;
return 0;
}
int wcsncmp(wchar_t const *s1, wchar_t const *s2, size_t n) {
size_t i;
for(i = 0; i != n && s1[i] && s2[i]; ++i) {
if(s1[i] != s2[i]) break;
}
if(s1[i] < s2[i]) return -1;
if(s1[i] > s2[i]) return 1;
return 0;
}
int wmemcmp(wchar_t const *s1, wchar_t const *s2, size_t n) {
// TODO: OOB when ranges are equal
size_t i;
for(i = 0; i != n; ++i) {
if(s1[i] != s2[i]) break;
}
if(s1[i] < s2[i]) return -1;
if(s1[i] > s2[i]) return 1;
return 0;
}

View File

@ -1,121 +0,0 @@
int iswctype(wint_t wc, wctype_t desc) {
return desc(wc);
}
wctype_t wctype(const char *property) {
if(!strcmp(property, "alnum")) return iswalnum;
if(!strcmp(property, "alpha")) return iswalpha;
if(!strcmp(property, "blank")) return iswblank;
if(!strcmp(property, "cntrl")) return iswcntrl;
if(!strcmp(property, "digit")) return iswdigit;
if(!strcmp(property, "graph")) return iswgraph;
if(!strcmp(property, "lower")) return iswlower;
if(!strcmp(property, "print")) return iswprint;
if(!strcmp(property, "punct")) return iswpunct;
if(!strcmp(property, "space")) return iswspace;
if(!strcmp(property, "upper")) return iswupper;
if(!strcmp(property, "xdigit")) return iswxdigit;
return NULL;
}
wint_t towctrans(wint_t wc, wctrans_t desc) {
return desc(wc);
}
wctrans_t wctrans(const char *property) {
if(!strcmp(property, "tolower")) return towlower;
if(!strcmp(property, "toupper")) return towupper;
return NULL;
}
int iswalnum(wint_t wc) {
return iswalpha(wc) || iswdigit(wc);
}
int iswalpha(wint_t wc) {
return iswupper(wc) || iswlower(wc);
}
int iswblank(wint_t wc) {
return wc == ' ' || wc == '\t';
}
int iswcntrl(wint_t wc) {
return 0;
//return uni_classify(wc) == UCHAR_Cc;
}
int iswdigit(wint_t wc) {
return '0' <= wc && wc <= '9';
}
int iswgraph(wint_t wc) {
return iswprint(wc) && !iswspace(wc);
}
int iswlower(wint_t wc) {
return 0;
// return uni_classify(wc) == UCHAR_Ll;
}
int iswprint(wint_t wc) {
// switch(uni_classify(wc)) {
// case UCHAR_Cc:
// case UCHAR_Cf:
// case UCHAR_Co:
// case UCHAR_Cs:
// return 0;
// }
return 1;
}
int iswpunct(wint_t wc) {
// switch(uni_classify(wc)) {
// case UCHAR_Pc:
// case UCHAR_Pd:
// case UCHAR_Pe:
// case UCHAR_Pf:
// case UCHAR_Pi:
// case UCHAR_Po:
// case UCHAR_Ps:
// case UCHAR_Sk:
// case UCHAR_Sc:
// case UCHAR_Sm:
// case UCHAR_So:
// return 1;
// }
return 0;
}
int iswspace(wint_t wc) {
switch(wc) {
case ' ':
case '\t':
case '\v':
case '\r':
case '\n':
case '\f':
return 1;
}
return 0;
}
int iswupper(wint_t wc) {
// return uni_classify(wc) == UCHAR_Lu;
return 0;
}
int iswxdigit(wint_t wc) {
return iswdigit(wc) || ('a'<=wc && wc<='f') || ('A'<= wc && wc<='F');
}
wint_t towlower(wint_t wc) {
// return uni_tolower(wc);
return wc;
}
wint_t towupper(wint_t wc) {
return wc;
// return uni_toupper(wc);
}

8
test.sh Executable file
View File

@ -0,0 +1,8 @@
#!/bin/bash
if [ "$1" != "-shared" ]; then
clang -static -nostdlib tests/empty.c lib/ciabatta.a -Iinclude
else
clang -fPIE tests/empty.c -c -o tests/empty.o
ld -no-pie -nostdlib lib/entry.o tests/empty.o lib/ciabatta.so lib/ctors.o -Iinclude
fi

View File

@ -1,799 +1,10 @@
// Framework for testing of the CRT library. This file is supposed to be linked
// to the ciabatta, so there is a possibility that the runtime that the testing
// suite relies on is broken, which is why to decrease the chance of it crashing
// because of that, I minimize that dependency. Therefore this testing suite
// avoids the following:
// - Heap allocations
// - Calls to high-level functions like printf, preferring low-level fwrite instead
// - Calling other CRT functions other than for the purpose of testing them
// Dependencies
#include <stddef.h>
#include <stdio.h>
#include <stdbool.h>
#include <stdarg.h>
#include <stdint.h>
#include <time.h>
// Tested
#include <stdint.h>
#include <limits.h>
#include <ctype.h>
// MEMORY
#define TEST_MEMORY_SIZE 8*1024*1024
static uint8_t test_memory[TEST_MEMORY_SIZE];
static uint64_t test_memory_head = TEST_MEMORY_SIZE;
static void *mem_alloc(uint64_t size) {
if(test_memory_head < size) {
fputs("Out of memory. Can't continue testing!!", stderr);
return NULL;
}
test_memory_head -= size;
return &test_memory[test_memory_head];
}
// RANDOM NUMBER GENERATOR (RNG)
static unsigned long random_seed = 0;
unsigned long random(void) {
random_seed = random_seed * 2147001325 + 715136305;
return 0x31415926 ^ ((random_seed >> 16) + (random_seed << 16));
}
unsigned long random_between(int lo, int hi) {
return (random() % (1+hi - lo)) + lo;
}
// FORMATTING AND IO
bool fmt_xml_escapes = false;
static void fprintc(FILE *file, char c) {
fputc(c, file);
}
static void fprints(FILE *file, char *str) {
while(*str != 0) {
fputc(*str++, file);
}
}
static void fprintc_maybe_xml(FILE *file, char c) {
if(c == '"' && fmt_xml_escapes) {
fprints(file, "&quot;");
}
else if(c == '&' && fmt_xml_escapes) {
fprints(file, "&amp;");
}
else if(c == '<' && fmt_xml_escapes) {
fprints(file, "&lt;");
}
else if(c == '>' && fmt_xml_escapes) {
fprints(file, "&gt;");
}
else if(c == '\'' && fmt_xml_escapes) {
fprints(file, "&apos;");
}
else {
fprintc(file, c);
}
}
static void fprintd(FILE *file, int32_t number, int width) {
if(number < 0) {
fprintc(file, '-');
number = -number;
}
char buffer[20] = {0};
char *str = buffer + sizeof buffer - 1;
do {
*--str = number%10+'0';
number /= 10;
} while(number != 0);
int num_digits = (int)((buffer + sizeof buffer - 1) - str);
int pad_width = width - num_digits;
while(pad_width-- > 0) {
fprintc(file, '0');
}
fprints(file, str);
}
static void fprintu(FILE *file, uint32_t number, int width) {
char buffer[20] = {0};
char *str = buffer + sizeof buffer;
do {
*--str = number%10+'0';
number /= 10;
} while(number != 0);
int num_digits = (int)((buffer + sizeof buffer - 1) - str);
int pad_width = width - num_digits;
while(pad_width-- > 0) {
fprintc(file, '0');
}
fprints(file, str);
}
static void fvprint_fmt(FILE *file, char *fmt, va_list args) {
while(*fmt != 0) {
if(*fmt != '%') {
fprintc(file, *fmt);
}
else {
++fmt;
int width = 0;
while('0' <= *fmt && *fmt <= '9') {
width = 10*width + *fmt-'0';
++fmt;
}
if(*fmt == 'c') {
int ch = va_arg(args, int);
fprintc_maybe_xml(file, ch);
}
else if(*fmt == '%') {
fprintc(file, '%');
}
else if(*fmt == 's') {
char *str = va_arg(args, char*);
while(*str != 0) {
fprintc_maybe_xml(file, *str);
++str;
}
}
else if(*fmt == 'd') {
int32_t i = va_arg(args, int32_t);
fprintd(file, i, width);
}
else if(*fmt == 'u') {
uint32_t u = va_arg(args, uint32_t);
fprintu(file, u, width);
}
}
++fmt;
}
}
static void fprint_fmt(FILE *file, char *fmt, ...) {
va_list args;
va_start(args, fmt);
fvprint_fmt(file, fmt, args);
va_end(args);
}
static void printc(char c) {
fprintc(stdout, c);
}
static void prints(char *str) {
fprints(stdout, str);
}
static void printd(int32_t number, int width) {
fprintd(stdout, number, width);
}
static void printu(uint32_t number, int width) {
fprintu(stdout, number, width);
}
static void print_fmt(char *fmt, ...) {
va_list args;
va_start(args, fmt);
fvprint_fmt(stdout, fmt, args);
va_end(args);
}
static void sprint_fmt(char *dst, char *fmt, ...) {
va_list args;
va_start(args, fmt);
while(*fmt != 0) {
if(*fmt != '%') {
*dst++ = *fmt;
}
else {
++fmt;
int width = 0;
while('0' <= *fmt && *fmt <= '9') {
width = 10*width + *fmt-'0';
++fmt;
}
if(*fmt == 'c') {
int ch = va_arg(args, int);
*dst++ = ch;
}
else if(*fmt == 's') {
char *str = va_arg(args, char*);
while((*dst++ = *str++));
}
else if(*fmt == 'd') {
int32_t i = va_arg(args, int32_t);
if(i < 0) {
i = -i;
*dst++ = '-';
}
char buffer[20] = {0};
char *str = buffer + sizeof buffer;
do {
*--str = i%10+'0';
i /= 10;
} while(i != 0);
int num_digits = (int)((buffer + sizeof buffer - 1) - str);
int pad_width = width - num_digits;
while(pad_width-- > 0) {
*dst++ = '0';
}
while((*dst++ = *str++));
}
else if(*fmt == 'u') {
uint32_t u = va_arg(args, uint32_t);
char buffer[20] = {0};
char *str = buffer + sizeof buffer;
do {
*--str = u%10+'0';
u /= 10;
} while(u != 0);
int num_digits = (int)((buffer + sizeof buffer - 1) - str);
int pad_width = width - num_digits;
while(pad_width-- > 0) {
*dst++ = '0';
}
while((*dst++ = *str++));
}
}
++fmt;
}
*dst = 0;
va_end(fmt);
}
static void term_color_green() {
prints("\x1b[32m");
}
static void term_color_red() {
prints("\x1b[31m");
}
static void term_color_yellow() {
prints("\x1b[33m");
}
static void term_color_reset() {
prints("\x1b[0m");
}
// TEST SUITE FUNCTIONS
// This stuff is for saving results of tests to be a bit more flexible with printing
// test results
struct Test typedef Test;
struct Test_Feature typedef Test_Feature;
struct Test_Feature {
Test_Feature *next;
char *name;
int test_count;
int success_count;
Test *test_head;
};
struct Test {
Test *next;
char *condition_str;
char *error_msg;
int line;
bool is_succeeded;
};
static Test_Feature *reverse_test_lists(Test_Feature *features_reversed) {
Test_Feature *new_head = NULL;
while(features_reversed != NULL) {
Test_Feature *reversed_next = features_reversed->next;
Test_Feature *new_prev = features_reversed;
new_prev->next = new_head;
new_head = new_prev;
features_reversed = reversed_next;
}
for(Test_Feature *feature = new_head; feature != NULL; feature = feature->next) {
Test *reversed_head = feature->test_head;
Test *head = NULL;
while(reversed_head != NULL) {
Test *reversed_next = reversed_head->next;
Test *head_prev = reversed_head;
head_prev->next = head;
head = head_prev;
reversed_head = reversed_next;
}
feature->test_head = head;
}
return new_head;
}
static void print_test_results(Test_Feature *features) {
prints(":: Printing test results\n");
// Iterate features
int total_test_count = 0;
int total_success_count = 0;
for(Test_Feature *feature = features; feature != NULL; feature = feature->next) {
// Update counters
total_test_count += feature->test_count;
total_success_count += feature->success_count;
// Print feature name
term_color_green();
print_fmt("==> Feature ");
term_color_reset();
print_fmt("%s: (%d/%d)\n", feature->name, feature->success_count, feature->test_count);
if(feature->success_count < feature->test_count) {
int test_index = 0;
for(Test *test = feature->test_head; test != NULL; test = test->next) {
if(!test->is_succeeded) {
term_color_red();
print_fmt(" Test #%d", 1+test_index);
term_color_reset();
print_fmt(" failed (line %d): %s\n", test->line, test->error_msg);
}
test_index += 1;
}
}
}
float success_percentage = (float) total_success_count / (float)total_test_count;
if(success_percentage < 0.5) {
term_color_red();
}
else if(success_percentage != 1.0) {
term_color_yellow();
}
else {
term_color_green();
}
time_t timestamp = time(NULL);
struct tm tm = *localtime(&timestamp);
print_fmt("[%4d-%2d-%2d %2d:%2d:%2d] ", 1900+tm.tm_year, 1+tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
prints("TESTS COMPLETED: ");
printd(total_success_count, 0);
printc('/');
printd(total_test_count, 0);
term_color_reset();
printc('\n');
}
// JUNIT OUTPUT
static void junit_write(char *path, Test_Feature *features) {
fmt_xml_escapes = true;
FILE *xml = fopen(path, "wb");
// TODO: store tests and failures in an object instead of calculating it like that
int total_test_count = 0;
int total_success_count = 0;
for(Test_Feature *feature = features; feature != NULL; feature = feature->next) {
total_test_count += feature->test_count;
total_success_count += feature->success_count;
}
fprint_fmt(xml, "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n");
fprint_fmt(xml, "<testsuites id=\"0\" name=\"%s\" tests=\"%d\" failures=\"%d\" time=\"0\">\n",
"Ciabatta CRT functions test suite", total_test_count, total_test_count - total_success_count);
int feature_id = 0;
for(Test_Feature *feature = features; feature != NULL; feature = feature->next) {
fprint_fmt(xml, " <testsuite id=\"%d\" name=\"%s\" tests=\"%d\" failures=\"%d\" time=\"0\">\n",
feature_id, feature->name, feature->test_count, feature->test_count - feature->success_count);
int test_id = 0;
for(Test *test = feature->test_head; test != NULL; test = test->next) {
fprint_fmt(xml, " <testcase id=\"%d\" name=\"%s\" time=\"0\">\n",
test_id, test->condition_str);
if(!test->is_succeeded) {
fprint_fmt(xml, " <failure message=\"crt.c(%d): %s\" type=\"ERROR\">\n",
test->line, test->error_msg);
fprint_fmt(xml, "crt.c(%d):\n %s\n", test->line, test->error_msg);
fprint_fmt(xml, " </failure>\n");
}
test_id += 1;
fprint_fmt(xml, " </testcase>\n");
}
feature_id += 1;
fprint_fmt(xml, " </testsuite>\n");
}
fprint_fmt(xml, "</testsuites>\n");
fclose(xml);
fmt_xml_escapes = false;
}
// TEST MACROS
#define XSTR(expr) #expr
#define STR(expr) XSTR(expr)
Test_Feature *current_feature = NULL;
bool junit_output = false;
char *junit_output_path = NULL;
#define JUNIT_START(XML_PATH) \
junit_output = true; \
junit_output_path = XML_PATH
#define JUNIT_END() \
if(junit_output) { \
junit_write(junit_output_path, current_feature); \
}
#define FEATURE_START__(NAME, NUMBER) \
{ \
print_fmt(":: Running tests for %s\n", NAME); \
Test_Feature *feature = mem_alloc(sizeof(Test_Feature)); \
feature->next = current_feature; \
current_feature = feature; \
current_feature->name = NAME; \
current_feature->test_head = NULL; \
current_feature->success_count = 0; \
current_feature->test_count = 0; \
}
#define FEATURE_START_(NAME, NUMBER) \
FEATURE_START__(NAME, NUMBER)
#define FEATURE_START(NAME) \
FEATURE_START_(NAME, __COUNTER__)
#define FEATURE_END()
#define TEST__(EXPR, ERROR_FMT, NUMBER, LINE, ...) \
{ \
Test *test = mem_alloc(sizeof(Test)); \
test->next = current_feature->test_head; \
current_feature->test_head = test; \
current_feature->test_head->condition_str = STR(EXPR); \
current_feature->test_head->is_succeeded = EXPR; \
current_feature->test_head->line = LINE; \
if(current_feature->test_head->is_succeeded) {\
current_feature->success_count += 1; \
}\
else { \
current_feature->test_head->error_msg = mem_alloc(256); \
sprint_fmt(current_feature->test_head->error_msg, ERROR_FMT, __VA_ARGS__); \
}\
current_feature->test_count += 1; \
}
#define TEST_(EXPR, ERROR_MSG, NUMBER, LINE, ...) \
TEST__(EXPR, ERROR_MSG, NUMBER, LINE, __VA_ARGS__)
#define TEST(EXPR, ERROR_MSG, ...) \
TEST_(EXPR, ERROR_MSG, __COUNTER__, __LINE__, __VA_ARGS__)
#define TESTS_PREPARE() \
current_feature = reverse_test_lists(current_feature)
#define TESTS_PRINT_RESULT() \
print_test_results(current_feature)
#include "testing.h"
int main(int argc, char **argv) {
JUNIT_START("test/junit.xml");
FEATURE_START("limits.h");
{
// Check existing of macro definitions
#ifdef BOOL_WIDTH
TEST(BOOL_WIDTH == 8*sizeof(bool), "BOOL_WIDTH isn't correlated with sizeof(bool)");
#else
TEST(false, "The macro BOOL_WIDTH wasn't defined");
#endif
#ifdef CHAR_WIDTH
TEST(CHAR_WIDTH == 8, "CHAR_WIDTH isn't 8");
#else
TEST(false, "The macro CHAR_WIDTH wasn't defined");
#endif
#ifdef CHAR_BIT
TEST(CHAR_BIT == 8, "CHAR_BIT isn't 8");
#else
TEST(false, "The macro CHAR_BIT wasn't defined");
#endif
#ifdef CHAR_MIN
TEST(CHAR_MIN == -128, "CHAR_MIN isn't -128");
#else
TEST(false, "The macro CHAR_MIN wasn't defined");
#endif
#ifdef CHAR_MAX
TEST(CHAR_MAX == 127, "CHAR_MAX isn't 127");
#else
TEST(false, "The macro CHAR_MAX wasn't defined");
#endif
#ifdef MB_LEN_MAX
TEST(true, "");
#else
TEST(false, "The macro MB_LEN_MAX wasn't defined");
#endif
#ifdef SCHAR_WIDTH
TEST(SCHAR_WIDTH == 8, "SCHAR_WIDTH isn't 8");
#else
TEST(false, "The macro SCHAR_WIDTH wasn't defined");
#endif
#ifdef SHRT_WIDTH
TEST(SHRT_WIDTH == 16, "SHRT_WIDTH isn't 16");
#else
TEST(false, "The macro SHRT_WIDTH wasn't defined");
#endif
#ifdef INT_WIDTH
TEST(INT_WIDTH == 32, "INT_WIDTH isn't 32");
#else
TEST(false, "The macro INT_WIDTH wasn't defined");
#endif
#ifdef LONG_WIDTH
TEST(LONG_WIDTH == 32, "LONG_WIDTH isn't 32");
#else
TEST(false, "The macro LONG_WIDTH wasn't defined");
#endif
#ifdef LLONG_WIDTH
TEST(LLONG_WIDTH == 64, "LLONG_WIDTH isn't 64");
#else
TEST(false, "The macro LLONG_WIDTH wasn't defined");
#endif
#ifdef SCHAR_MIN
TEST(SCHAR_MIN == -128, "SCHAR_MIN isn't -128");
#else
TEST(false, "The macro SCHAR_MIN wasn't defined");
#endif
#ifdef SHRT_MIN
TEST(SHRT_MIN == -0x8000, "SHRT_MIN isn't -0x8000");
#else
TEST(false, "The macro SHRT_MIN wasn't defined");
#endif
#ifdef INT_MIN
TEST(INT_MIN == -0x80000000, "INT_MIN isn't -0x80000000");
#else
TEST(false, "The macro INT_MIN wasn't defined");
#endif
#ifdef LONG_MIN
TEST(LONG_MIN == -0x80000000l, "LONG_MIN isn't -0x80000000");
#else
TEST(false, "The macro LONG_MIN wasn't defined");
#endif
#ifdef LLONG_MIN
TEST(LLONG_MIN == -0x8000000000000000ll, "LLONG_MIN isn't -0x8000000000000000");
#else
TEST(false, "The macro LLONG_MIN wasn't defined");
#endif
#ifdef SCHAR_MAX
TEST(SCHAR_MAX == 127, "SCHAR_MAX isn't 127");
#else
TEST(false, "The macro SCHAR_MAX wasn't defined");
#endif
#ifdef SHRT_MAX
TEST(SHRT_MAX == 0x7fff, "SHRT_MAX isn't 0x7fff");
#else
TEST(false, "The macro SHRT_MAX wasn't defined");
#endif
#ifdef INT_MAX
TEST(INT_MAX == 0x7fffffff, "INT_MAX isn't 0x7fffffff");
#else
TEST(false, "The macro INT_MAX wasn't defined");
#endif
#ifdef LONG_MAX
TEST(LONG_MAX == 0x7fffffff, "LONG_MAX isn't 0x7fffffff");
#else
TEST(false, "The macro LONG_MAX wasn't defined");
#endif
#ifdef LLONG_MAX
TEST(LLONG_MAX == 0x7fffffffffffffffll, "LLONG_MAX isn't 0x7fffffffffffffff");
#else
TEST(false, "The macro LLONG_MAX wasn't defined");
#endif
#ifdef UCHAR_WIDTH
TEST(UCHAR_WIDTH == 8, "UCHAR_WIDTH isn't 8");
#else
TEST(false, "The macro UCHAR_WIDTH wasn't defined");
#endif
#ifdef USHRT_WIDTH
TEST(USHRT_WIDTH == 16, "USHRT_WIDTH isn't 16");
#else
TEST(false, "The macro USHRT_WIDTH wasn't defined");
#endif
#ifdef UINT_WIDTH
TEST(UINT_WIDTH == 32, "UINT_WIDTH isn't 32");
#else
TEST(false, "The macro UINT_WIDTH wasn't defined");
#endif
#ifdef ULONG_WIDTH
TEST(ULONG_WIDTH == 32, "ULONG_WIDTH isn't 32");
#else
TEST(false, "The macro ULONG_WIDTH wasn't defined");
#endif
#ifdef ULLONG_WIDTH
TEST(ULLONG_WIDTH == 64, "ULLONG_WIDTH isn't 64");
#else
TEST(false, "The macro ULLONG_WIDTH wasn't defined");
#endif
#ifdef UCHAR_MAX
TEST(UCHAR_MAX == 255, "UCHAR_MAX isn't 255");
#else
TEST(false, "The macro UCHAR_MAX wasn't defined");
#endif
#ifdef USHRT_MAX
TEST(USHRT_MAX == 0xffffu, "USHRT_MAX isn't 0xffff");
#else
TEST(false, "The macro USHRT_MAX wasn't defined");
#endif
#ifdef UINT_MAX
TEST(UINT_MAX == 0xffffffffu, "UINT_MAX isn't 0xffffffff");
#else
TEST(false, "The macro UINT_MAX wasn't defined");
#endif
#ifdef ULONG_MAX
TEST(ULONG_MAX == 0xffffffffu, "ULONG_MAX isn't 0xffffffff");
#else
TEST(false, "The macro ULONG_MAX wasn't defined");
#endif
#ifdef ULLONG_MAX
TEST(ULLONG_MAX == 0xffffffffffffffffull, "ULLONG_MAX isn't 0xffffffffffffffffull");
#else
TEST(false, "The macro ULLONG_MAX wasn't defined");
#endif
#ifdef PTRDIFF_WIDTH
TEST(true, "");
#else
TEST(false, "The macro PTRDIFF_WIDTH isn't defined");
#endif
#ifdef PTRDIFF_MIN
TEST(true, "");
#else
TEST(false, "The macro PTRDIFF_MIN isn't defined");
#endif
#ifdef PTRDIFF_MAX
TEST(true, "");
#else
TEST(false, "The macro PTRDIFF_MAX isn't defined");
#endif
#ifdef SIZE_WIDTH
TEST(true, "");
#else
TEST(false, "The macro SIZE_WIDTH isn't defined");
#endif
#ifdef SIZE_MAX
TEST(true, "");
#else
TEST(false, "The macro SIZE_MAX isn't defined");
#endif
#ifdef SIG_ATOMIC_WIDTH
TEST(true, "");
#else
TEST(false, "The macro SIG_ATOMIC_WIDTH isn't defined");
#endif
#ifdef SIG_ATOMIC_MIN
TEST(true, "");
#else
TEST(false, "The macro SIG_ATOMIC_MIN isn't defined");
#endif
#ifdef SIG_ATOMIC_MAX
TEST(true, "");
#else
TEST(false, "The macro SIG_ATOMIC_MAX isn't defined");
#endif
#ifdef WINT_WIDTH
TEST(true, "");
#else
TEST(false, "The macro WINT_WIDTH isn't defined");
#endif
#ifdef WINT_MIN
TEST(true, "");
#else
TEST(false, "The macro WINT_MIN isn't defined");
#endif
#ifdef WINT_MAX
TEST(true, "");
#else
TEST(false, "The macro WINT_MAX isn't defined");
#endif
#ifdef WCHAR_WIDTH
TEST(true, "");
#else
TEST(false, "The macro WCHAR_WIDTH isn't defined");
#endif
#ifdef WCHAR_MIN
TEST(true, "");
#else
TEST(false, "WCHAR_MIN isn't defined");
#endif
#ifdef WCHAR_MAX
TEST(true, "");
#else
TEST(false, "WCHAR_MAX isn't defined");
#endif
}
FEATURE_END();
FEATURE_START("ctype.h");
{
// Test letters
for(int i = 0; i != 10; ++i) {
int letter = random_between('a', 'z');
TEST(isalpha(letter) != 0, "isalpha('%c') returned false", letter);
TEST(isdigit(letter) == 0, "isdigit('%c') returned true", letter);
}
// Test digits
for(int i = 0; i != 10; ++i) {
int digit = random_between('0', '9');
TEST(isalpha(digit) == 0, "isalpha('%c') returned true", digit);
TEST(isdigit(digit) != 0, "isdigit('%c') returned false", digit);
}
}
FEATURE_END();
FEATURE_START("IO functions (stdio.h)");
{
static int numbers[10] = {0,1,2,3,4,5,6,7,8,9};
// fread/fwrite
{
FILE *file = fopen("test_folder/file", "wb");
TEST(file != NULL, "Created file is NULL");
int cnt_written = fwrite(numbers, sizeof(int), 10, file);
TEST(cnt_written == 10, "fwrite didn't write all 10 objects");
TEST(fclose(file) == 0, "fclose didn't close the file");
TEST(rename("test_folder/file", "test_folder/file2") == 0, "Rename returned 0");
file = fopen("test_folder/file2", "rb");
TEST(file != NULL, "Created file is NULL");
int read_numbers[10];
int cnt_read = fread(read_numbers, sizeof(int), 10, file);
TEST(cnt_read == 10, "fread didn't read 10 objects");
bool all_ok = true;
for(int i = 0; i != 10; ++i) {
if(read_numbers[i] != numbers[i]) {
all_ok = false;
break;
}
}
TEST(all_ok, "The elements read didn't match the elements written");
TEST(fclose(file) == 0, "fclose didn't close the file");
TEST(remove("test_folder/file2") == 0, "remove didn't remove the file");
}
// Seeking and stuff
{
FILE *file = fopen("test_folder/seek", "wb");
TEST(file != NULL, "Created file is NULL");
TEST(fwrite(numbers, sizeof(int), 10, file) == 10, "fwrite didn't write all 10 objects");
TEST(fflush(file) == 0, "fflush failed");
TEST(fseek(file, 4*sizeof(int), SEEK_SET) == 0, "fseek couldn't seek to offset 4");
int num;
TEST(fread(&num, sizeof(int), 1, file) == 1, "fread didn't read the int");
TEST(num == 4, "Wrong value read at offset 4");
TEST(fseek(file, -4, SEEK_END) == 0, "fseek coudn't seek to the end");
TEST(fread(&num, sizeof(int), 1, file) == 1, "fread didn't read the int");
TEST(num == 9, "Wrong number read");
TEST(fclose(file) == 0, "fclose didn't close the file");
file = fopen("test_folder/seek", "wb");
TEST(file != NULL, "Created file is NULL");
fpos_t nul_pos;
TEST(fgetpos(file, &nul_pos) == 0, "Couldn't get file position");
TEST(fseek(file, 0, SEEK_END) == 0, "Couldn't seek to the end of the file");
long file_size = ftell(file);
TEST(file_size != -1L, "ftell failed");
TEST(fsetpos(file, &nul_pos) == 0, "Couldn't reset file position");
TEST(ftell(file) == 0, "File position reset to wrong spot");
}
// Getchar, ungetchar
{
char str[] = "Hello, world!";
FILE *file = fopen("test_folder/getc", "wb");
TEST(file != NULL, "Created file is NULL");
TEST(fputs(str, file) >= 0, "fputs failed");
TEST(fputc('!', file) == '!', "fputc failed");
TEST(fflush(file) == 0, "fflush failed");
// TEST(fclose(file) == 0, "fclose failed");
file = freopen("test_folder/getc", "rb", file);
TEST(file != NULL, "Reopened file is NULL");
TEST(fgets(str, sizeof str, file) == str, "fgets failed");
TEST(fgetc(file) == '!', "fgetc read the wrong thing");
TEST(ungetc('?', file) == '?', "ungetc failed to put a character");
TEST(fgetc(file) == '?', "Didn't get back the same character that we unget'ed");
TEST(fclose(file) == 0, "fclose failed");
}
}
FEATURE_START("My feature");
TEST(1 == 1, "Tests work");
TESTS_PREPARE();
TESTS_PRINT_RESULT();
JUNIT_END();

4
tests/empty.c Normal file
View File

@ -0,0 +1,4 @@
int main() {
return 0;
}

471
tests/testing.h Normal file
View File

@ -0,0 +1,471 @@
// Framework for testing of the CRT library. This file is supposed to be linked
// to the ciabatta, so there is a possibility that the runtime that the testing
// suite relies on is broken, which is why to decrease the chance of it crashing
// because of that, I minimize that dependency. Therefore this testing suite
// avoids the following:
// - Heap allocations
// - Calls to high-level functions like printf, preferring low-level fwrite instead
// - Calling other CRT functions other than for the purpose of testing them
// Dependencies
#include <stddef.h>
#include <stdio.h>
#include <stdbool.h>
#include <stdarg.h>
#include <stdint.h>
#include <time.h>
// Tested
#include <stdint.h>
#include <limits.h>
#include <ctype.h>
// MEMORY
#define TEST_MEMORY_SIZE 8*1024*1024
static uint8_t test_memory[TEST_MEMORY_SIZE];
static uint64_t test_memory_head = TEST_MEMORY_SIZE;
static void *mem_alloc(uint64_t size) {
if(test_memory_head < size) {
fputs("Out of memory. Can't continue testing!!", stderr);
return NULL;
}
test_memory_head -= size;
return &test_memory[test_memory_head];
}
// RANDOM NUMBER GENERATOR (RNG)
static unsigned long random_seed = 0;
unsigned long random(void) {
random_seed = random_seed * 2147001325 + 715136305;
return 0x31415926 ^ ((random_seed >> 16) + (random_seed << 16));
}
unsigned long random_between(int lo, int hi) {
return (random() % (1+hi - lo)) + lo;
}
// FORMATTING AND IO
bool fmt_xml_escapes = false;
static void fprintc(FILE *file, char c) {
fputc(c, file);
}
static void fprints(FILE *file, char *str) {
while(*str != 0) {
fputc(*str++, file);
}
}
static void fprintc_maybe_xml(FILE *file, char c) {
if(c == '"' && fmt_xml_escapes) {
fprints(file, "&quot;");
}
else if(c == '&' && fmt_xml_escapes) {
fprints(file, "&amp;");
}
else if(c == '<' && fmt_xml_escapes) {
fprints(file, "&lt;");
}
else if(c == '>' && fmt_xml_escapes) {
fprints(file, "&gt;");
}
else if(c == '\'' && fmt_xml_escapes) {
fprints(file, "&apos;");
}
else {
fprintc(file, c);
}
}
static void fprintd(FILE *file, int32_t number, int width) {
if(number < 0) {
fprintc(file, '-');
number = -number;
}
char buffer[20] = {0};
char *str = buffer + sizeof buffer - 1;
do {
*--str = number%10+'0';
number /= 10;
} while(number != 0);
int num_digits = (int)((buffer + sizeof buffer - 1) - str);
int pad_width = width - num_digits;
while(pad_width-- > 0) {
fprintc(file, '0');
}
fprints(file, str);
}
static void fprintu(FILE *file, uint32_t number, int width) {
char buffer[20] = {0};
char *str = buffer + sizeof buffer;
do {
*--str = number%10+'0';
number /= 10;
} while(number != 0);
int num_digits = (int)((buffer + sizeof buffer - 1) - str);
int pad_width = width - num_digits;
while(pad_width-- > 0) {
fprintc(file, '0');
}
fprints(file, str);
}
static void fvprint_fmt(FILE *file, char *fmt, va_list args) {
while(*fmt != 0) {
if(*fmt != '%') {
fprintc(file, *fmt);
}
else {
++fmt;
int width = 0;
while('0' <= *fmt && *fmt <= '9') {
width = 10*width + *fmt-'0';
++fmt;
}
if(*fmt == 'c') {
int ch = va_arg(args, int);
fprintc_maybe_xml(file, ch);
}
else if(*fmt == '%') {
fprintc(file, '%');
}
else if(*fmt == 's') {
char *str = va_arg(args, char*);
while(*str != 0) {
fprintc_maybe_xml(file, *str);
++str;
}
}
else if(*fmt == 'd') {
int32_t i = va_arg(args, int32_t);
fprintd(file, i, width);
}
else if(*fmt == 'u') {
uint32_t u = va_arg(args, uint32_t);
fprintu(file, u, width);
}
}
++fmt;
}
}
static void fprint_fmt(FILE *file, char *fmt, ...) {
va_list args;
va_start(args, fmt);
fvprint_fmt(file, fmt, args);
va_end(args);
}
static void printc(char c) {
fprintc(stdout, c);
}
static void prints(char *str) {
fprints(stdout, str);
}
static void printd(int32_t number, int width) {
fprintd(stdout, number, width);
}
static void printu(uint32_t number, int width) {
fprintu(stdout, number, width);
}
static void print_fmt(char *fmt, ...) {
va_list args;
va_start(args, fmt);
fvprint_fmt(stdout, fmt, args);
va_end(args);
}
static void sprint_fmt(char *dst, char *fmt, ...) {
va_list args;
va_start(args, fmt);
while(*fmt != 0) {
if(*fmt != '%') {
*dst++ = *fmt;
}
else {
++fmt;
int width = 0;
while('0' <= *fmt && *fmt <= '9') {
width = 10*width + *fmt-'0';
++fmt;
}
if(*fmt == 'c') {
int ch = va_arg(args, int);
*dst++ = ch;
}
else if(*fmt == 's') {
char *str = va_arg(args, char*);
while((*dst++ = *str++));
}
else if(*fmt == 'd') {
int32_t i = va_arg(args, int32_t);
if(i < 0) {
i = -i;
*dst++ = '-';
}
char buffer[20] = {0};
char *str = buffer + sizeof buffer;
do {
*--str = i%10+'0';
i /= 10;
} while(i != 0);
int num_digits = (int)((buffer + sizeof buffer - 1) - str);
int pad_width = width - num_digits;
while(pad_width-- > 0) {
*dst++ = '0';
}
while((*dst++ = *str++));
}
else if(*fmt == 'u') {
uint32_t u = va_arg(args, uint32_t);
char buffer[20] = {0};
char *str = buffer + sizeof buffer;
do {
*--str = u%10+'0';
u /= 10;
} while(u != 0);
int num_digits = (int)((buffer + sizeof buffer - 1) - str);
int pad_width = width - num_digits;
while(pad_width-- > 0) {
*dst++ = '0';
}
while((*dst++ = *str++));
}
}
++fmt;
}
*dst = 0;
va_end(fmt);
}
static void term_color_green() {
prints("\x1b[32m");
}
static void term_color_red() {
prints("\x1b[31m");
}
static void term_color_yellow() {
prints("\x1b[33m");
}
static void term_color_reset() {
prints("\x1b[0m");
}
// TEST SUITE FUNCTIONS
// This stuff is for saving results of tests to be a bit more flexible with printing
// test results
struct Test typedef Test;
struct Test_Feature typedef Test_Feature;
struct Test_Feature {
Test_Feature *next;
char *name;
int test_count;
int success_count;
Test *test_head;
};
struct Test {
Test *next;
char *condition_str;
char *error_msg;
int line;
bool is_succeeded;
};
static Test_Feature *reverse_test_lists(Test_Feature *features_reversed) {
Test_Feature *new_head = NULL;
while(features_reversed != NULL) {
Test_Feature *reversed_next = features_reversed->next;
Test_Feature *new_prev = features_reversed;
new_prev->next = new_head;
new_head = new_prev;
features_reversed = reversed_next;
}
for(Test_Feature *feature = new_head; feature != NULL; feature = feature->next) {
Test *reversed_head = feature->test_head;
Test *head = NULL;
while(reversed_head != NULL) {
Test *reversed_next = reversed_head->next;
Test *head_prev = reversed_head;
head_prev->next = head;
head = head_prev;
reversed_head = reversed_next;
}
feature->test_head = head;
}
return new_head;
}
static void print_test_results(Test_Feature *features) {
prints(":: Printing test results\n");
// Iterate features
int total_test_count = 0;
int total_success_count = 0;
for(Test_Feature *feature = features; feature != NULL; feature = feature->next) {
// Update counters
total_test_count += feature->test_count;
total_success_count += feature->success_count;
// Print feature name
term_color_green();
print_fmt("==> Feature ");
term_color_reset();
print_fmt("%s: (%d/%d)\n", feature->name, feature->success_count, feature->test_count);
if(feature->success_count < feature->test_count) {
int test_index = 0;
for(Test *test = feature->test_head; test != NULL; test = test->next) {
if(!test->is_succeeded) {
term_color_red();
print_fmt(" Test #%d", 1+test_index);
term_color_reset();
print_fmt(" failed (line %d): %s\n", test->line, test->error_msg);
}
test_index += 1;
}
}
}
float success_percentage = (float) total_success_count / (float)total_test_count;
if(success_percentage < 0.5) {
term_color_red();
}
else if(success_percentage != 1.0) {
term_color_yellow();
}
else {
term_color_green();
}
time_t timestamp = time(NULL);
struct tm tm = *localtime(&timestamp);
print_fmt("[%4d-%2d-%2d %2d:%2d:%2d] ", 1900+tm.tm_year, 1+tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
prints("TESTS COMPLETED: ");
printd(total_success_count, 0);
printc('/');
printd(total_test_count, 0);
term_color_reset();
printc('\n');
}
// JUNIT OUTPUT
static void junit_write(char *path, Test_Feature *features) {
fmt_xml_escapes = true;
FILE *xml = fopen(path, "wb");
// TODO: store tests and failures in an object instead of calculating it like that
int total_test_count = 0;
int total_success_count = 0;
for(Test_Feature *feature = features; feature != NULL; feature = feature->next) {
total_test_count += feature->test_count;
total_success_count += feature->success_count;
}
fprint_fmt(xml, "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n");
fprint_fmt(xml, "<testsuites id=\"0\" name=\"%s\" tests=\"%d\" failures=\"%d\" time=\"0\">\n",
"Ciabatta CRT functions test suite", total_test_count, total_test_count - total_success_count);
int feature_id = 0;
for(Test_Feature *feature = features; feature != NULL; feature = feature->next) {
fprint_fmt(xml, " <testsuite id=\"%d\" name=\"%s\" tests=\"%d\" failures=\"%d\" time=\"0\">\n",
feature_id, feature->name, feature->test_count, feature->test_count - feature->success_count);
int test_id = 0;
for(Test *test = feature->test_head; test != NULL; test = test->next) {
fprint_fmt(xml, " <testcase id=\"%d\" name=\"%s\" time=\"0\">\n",
test_id, test->condition_str);
if(!test->is_succeeded) {
fprint_fmt(xml, " <failure message=\"crt.c(%d): %s\" type=\"ERROR\">\n",
test->line, test->error_msg);
fprint_fmt(xml, "crt.c(%d):\n %s\n", test->line, test->error_msg);
fprint_fmt(xml, " </failure>\n");
}
test_id += 1;
fprint_fmt(xml, " </testcase>\n");
}
feature_id += 1;
fprint_fmt(xml, " </testsuite>\n");
}
fprint_fmt(xml, "</testsuites>\n");
fclose(xml);
fmt_xml_escapes = false;
}
// TEST MACROS
#define XSTR(expr) #expr
#define STR(expr) XSTR(expr)
Test_Feature *current_feature = NULL;
bool junit_output = false;
char *junit_output_path = NULL;
#define JUNIT_START(XML_PATH) \
junit_output = true; \
junit_output_path = XML_PATH
#define JUNIT_END() \
if(junit_output) { \
junit_write(junit_output_path, current_feature); \
}
#define FEATURE_START__(NAME, NUMBER) \
{ \
print_fmt(":: Running tests for %s\n", NAME); \
Test_Feature *feature = mem_alloc(sizeof(Test_Feature)); \
feature->next = current_feature; \
current_feature = feature; \
current_feature->name = NAME; \
current_feature->test_head = NULL; \
current_feature->success_count = 0; \
current_feature->test_count = 0; \
}
#define FEATURE_START_(NAME, NUMBER) \
FEATURE_START__(NAME, NUMBER)
#define FEATURE_START(NAME) \
FEATURE_START_(NAME, __COUNTER__)
#define FEATURE_END()
#define TEST__(EXPR, ERROR_FMT, NUMBER, LINE, ...) \
{ \
Test *test = mem_alloc(sizeof(Test)); \
test->next = current_feature->test_head; \
current_feature->test_head = test; \
current_feature->test_head->condition_str = STR(EXPR); \
current_feature->test_head->is_succeeded = EXPR; \
current_feature->test_head->line = LINE; \
if(current_feature->test_head->is_succeeded) {\
current_feature->success_count += 1; \
}\
else { \
current_feature->test_head->error_msg = mem_alloc(256); \
sprint_fmt(current_feature->test_head->error_msg, ERROR_FMT, __VA_ARGS__); \
}\
current_feature->test_count += 1; \
}
#define TEST_(EXPR, ERROR_MSG, NUMBER, LINE, ...) \
TEST__(EXPR, ERROR_MSG, NUMBER, LINE, __VA_ARGS__)
#define TEST(EXPR, ERROR_MSG, ...) \
TEST_(EXPR, ERROR_MSG, __COUNTER__, __LINE__, __VA_ARGS__)
#define TESTS_PREPARE() \
current_feature = reverse_test_lists(current_feature)
#define TESTS_PRINT_RESULT() \
print_test_results(current_feature)

View File

@ -1,20 +0,0 @@
#include <stdio.h>
#include <Windows.h>
#pragma comment(lib, "user32.lib")
int main(int argc, char **argv) {
// Print args:
printf("Arguments:\n");
for(int i = 0; i != argc; ++i) {
char *arg = argv[i];
printf(" %s\n", arg);
}
// Test UTF-8 support:
printf(u8"Привет, мир!\n");
printf(u8"こんにちくわ世界!\n");
// Try UTF-8 in winapi (doesn't use UTF-8 without manifest)
MessageBoxA(NULL, u8"Успех", u8"Ошибка", MB_OK);
return 0;
}

View File

@ -1,57 +0,0 @@
#include <assert.h>
#include <windows.h>
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE p, LPSTR pCmdLine, int nCmdShow) {
const char CLASS_NAME[] = "Sample Window Class";
assert(0);
WNDCLASS wc = {
.lpfnWndProc = WindowProc,
.hInstance = hInstance,
.lpszClassName = CLASS_NAME,
};
RegisterClass(&wc);
HWND hwnd = CreateWindowEx(
0,
CLASS_NAME,
"Learn to Program Windows",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL
);
if (hwnd == NULL) {
return 0;
}
ShowWindow(hwnd, nCmdShow);
MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg)
{
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
// All painting occurs here, between BeginPaint and EndPaint.
FillRect(hdc, &ps.rcPaint, (HBRUSH) (COLOR_WINDOW+1));
EndPaint(hwnd, &ps);
}
return 0;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}