mirror of https://github.com/flysand7/ciabatta.git
Separate out platform stuff
This commit is contained in:
parent
4c09cdcca4
commit
88ef3bf81f
2
bake.cmd
2
bake.cmd
|
@ -31,7 +31,7 @@ mkdir bin\%PLATFORM%
|
||||||
del ciabatta.lib 2> nul
|
del ciabatta.lib 2> nul
|
||||||
for /R src\%PLATFORM% %%F in (*.c) do (
|
for /R src\%PLATFORM% %%F in (*.c) do (
|
||||||
echo %%F
|
echo %%F
|
||||||
clang -c -o bin\%PLATFORM%\%%~nF.obj %%F %CIABATTA_OPTIONS%
|
clang -Isrc/win -c -o bin\%PLATFORM%\%%~nF.obj %%F %CIABATTA_OPTIONS%
|
||||||
)
|
)
|
||||||
for /R src\code %%F in (*.c) do (
|
for /R src\code %%F in (*.c) do (
|
||||||
echo %%F
|
echo %%F
|
||||||
|
|
|
@ -1,26 +0,0 @@
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#if defined(_MSC_VER) && !defined(__clang__)
|
|
||||||
#define _compiler_msvc
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(__GNUC__) && !defined(__clang__)
|
|
||||||
#define _compiler_gcc
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(__clang__)
|
|
||||||
#define _compiler_clang
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(__CUIKC__)
|
|
||||||
#define _compiler_cuik
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !(defined(_compiler_msvc) \
|
|
||||||
|| defined(_compiler_gcc) \
|
|
||||||
|| defined(_compiler_cuik) \
|
|
||||||
|| defined(_compiler_clang))
|
|
||||||
#error "Unsupported Compiler"
|
|
||||||
#endif
|
|
||||||
|
|
43
inc/_os.h
43
inc/_os.h
|
@ -1,43 +0,0 @@
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
#if defined(_WIN32)
|
|
||||||
#define _os_win
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(__linux__) && !defined(__ANDROID__)
|
|
||||||
#define _os_linux
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !(defined(_os_win) \
|
|
||||||
|| defined(_os_linux))
|
|
||||||
#error "Unsupported OS"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// OS-dependent IO Functions
|
|
||||||
|
|
||||||
// TODO: see if we need this or will it be easier for linux to just pass
|
|
||||||
// the mode string.
|
|
||||||
typedef struct _OS_ModeFlags {
|
|
||||||
int base_mode;
|
|
||||||
int binary;
|
|
||||||
int update;
|
|
||||||
int exclusive;
|
|
||||||
} _OS_ModeFlags;
|
|
||||||
|
|
||||||
typedef struct FILE FILE;
|
|
||||||
|
|
||||||
void _os_print_stack_trace();
|
|
||||||
|
|
||||||
int _os_del_file(char const *filename);
|
|
||||||
int _os_mov_file(char const *old, char const *new);
|
|
||||||
char *_os_tmpname(char *buffer);
|
|
||||||
FILE *_os_fopen(char const *restrict name, _OS_ModeFlags flags);
|
|
||||||
int _os_fclose(FILE *file);
|
|
||||||
void _os_file_write(void* ctx, size_t n, const char str[]);
|
|
||||||
void _os_file_write_char(void* ctx, char ch);
|
|
||||||
|
|
||||||
void _os_init_eh();
|
|
||||||
|
|
||||||
_Noreturn void _os_exit(int code);
|
|
|
@ -1,55 +0,0 @@
|
||||||
#pragma once
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
|
|
||||||
// Microsoft uses this to refer to the secure functions so we'll allow it
|
|
||||||
#ifdef __STDC_WANT_SECURE_LIB__
|
|
||||||
#define __STDC_WANT_LIB_EXT1__ 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Compiler Identification
|
|
||||||
|
|
||||||
#if defined(_MSC_VER) && !defined(__clang__)
|
|
||||||
#define _compiler_msvc
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(__GNUC__) && !defined(__clang__)
|
|
||||||
#define _compiler_gnu
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(__clang__)
|
|
||||||
#define _compiler_clang
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(__CUIKC__)
|
|
||||||
#define _compiler_cuik
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !(defined(_compiler_msvc) \
|
|
||||||
|| defined(_compiler_gnu) \
|
|
||||||
|| defined(_compiler_cuik) \
|
|
||||||
|| defined(_compiler_clang))
|
|
||||||
#error "Unsupported Compiler"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// OS Identification
|
|
||||||
|
|
||||||
#if defined(_WIN32)
|
|
||||||
#define _os_win
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(__linux__) && !defined(__ANDROID__)
|
|
||||||
#define _os_linux
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !(defined(_os_win) \
|
|
||||||
|| defined(_os_linux))
|
|
||||||
#error "Unsupported OS"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __STDC_WANT_LIB_EXT1__
|
|
||||||
typedef int errno_t;
|
|
||||||
typedef size_t rsize_t;
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#if !defined(__func__)
|
#if !defined(__func__)
|
||||||
|
|
|
@ -1,21 +0,0 @@
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
|
|
||||||
#include <stdio.h> // printf
|
|
||||||
#include <stdlib.h> // abort
|
|
||||||
#include <_os.h> // stack trace
|
|
||||||
|
|
||||||
void _Noreturn _assert(
|
|
||||||
char const *cond,
|
|
||||||
char const *func,
|
|
||||||
char const *file,
|
|
||||||
int line
|
|
||||||
) {
|
|
||||||
printf("Assertion failed: %s\n", cond);
|
|
||||||
printf(" Function: %s\n", func);
|
|
||||||
printf(" File: %s\n", file);
|
|
||||||
printf(" Line: %d\n", line);
|
|
||||||
printf("Trace:\n");
|
|
||||||
_os_print_stack_trace();
|
|
||||||
abort();
|
|
||||||
}
|
|
|
@ -8,8 +8,7 @@
|
||||||
#define asuint64(x) ((union {double f; uint64_t i;}){x}).i
|
#define asuint64(x) ((union {double f; uint64_t i;}){x}).i
|
||||||
#define asdouble(x) ((union {double f; uint64_t i;}){x}).f
|
#define asdouble(x) ((union {double f; uint64_t i;}){x}).f
|
||||||
|
|
||||||
#include <_compiler.h>
|
#if defined(__GNUC__) || defined(__clang__)
|
||||||
#if defined(_compiler_clang) || defined(_compiler_gcc)
|
|
||||||
#define just_do_it(t) __attribute__((unused)) volatile t
|
#define just_do_it(t) __attribute__((unused)) volatile t
|
||||||
#else
|
#else
|
||||||
#define just_do_it(t) volatile t
|
#define just_do_it(t) volatile t
|
||||||
|
|
|
@ -1,46 +0,0 @@
|
||||||
|
|
||||||
#include <_os.h>
|
|
||||||
#include <signal.h>
|
|
||||||
|
|
||||||
void _signal_default_handler(int sig)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void _signal_ignore_handler(int sig)
|
|
||||||
{
|
|
||||||
// ignore :kekw:
|
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
|
||||||
_os_exit(-69420);
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
|
@ -1,65 +0,0 @@
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <_os.h>
|
|
||||||
|
|
||||||
FILE *stdout;
|
|
||||||
FILE *stderr;
|
|
||||||
FILE *stdin;
|
|
||||||
|
|
||||||
int remove(const char *filename)
|
|
||||||
{
|
|
||||||
return _os_del_file(filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
int rename(const char *old, const char *new)
|
|
||||||
{
|
|
||||||
return _os_mov_file(old, new);
|
|
||||||
}
|
|
||||||
|
|
||||||
char *tmpnam(char *s) {
|
|
||||||
static char static_buffer[L_tmpnam];
|
|
||||||
char *buffer = s;
|
|
||||||
if(s == NULL) buffer = static_buffer;
|
|
||||||
return _os_tmpname(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
FILE *fopen(const char *restrict filename, const char *restrict mode)
|
|
||||||
{
|
|
||||||
// Basically defined UB here by introducing missing modes
|
|
||||||
// It is simpler to implement that way I think.
|
|
||||||
int base_mode = mode[0];
|
|
||||||
int binary = 0;
|
|
||||||
int exclusive = 0;
|
|
||||||
int update = 0;
|
|
||||||
for(; *mode != 0; ++mode) {
|
|
||||||
if(*mode == 'x') exclusive = 1;
|
|
||||||
if(*mode == 'b') binary = 1;
|
|
||||||
if(*mode == '+') update = 1;
|
|
||||||
}
|
|
||||||
if(base_mode == 'r' && exclusive) return NULL;
|
|
||||||
if(base_mode == 'a' && exclusive) return NULL;
|
|
||||||
|
|
||||||
_OS_ModeFlags mode_flags = {
|
|
||||||
.base_mode = base_mode,
|
|
||||||
.binary = binary,
|
|
||||||
.update = update,
|
|
||||||
.exclusive = exclusive,
|
|
||||||
};
|
|
||||||
|
|
||||||
return _os_fopen(filename, mode_flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
int fclose(FILE *stream)
|
|
||||||
{
|
|
||||||
return _os_fclose(stream);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO:kekw:
|
|
||||||
FILE *freopen(
|
|
||||||
const char *restrict filename,
|
|
||||||
const char *restrict mode,
|
|
||||||
FILE *restrict stream)
|
|
||||||
{
|
|
||||||
fclose(stream);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
|
@ -1,723 +0,0 @@
|
||||||
|
|
||||||
#include <math.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <limits.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <math.h>
|
|
||||||
|
|
||||||
// This stuff is kinda related to what's going on in this file, so I left it
|
|
||||||
// in a rather ugly manner here.
|
|
||||||
#if !defined(once)
|
|
||||||
#define once
|
|
||||||
|
|
||||||
#define countof(arr) (sizeof(arr)/sizeof(arr[0]))
|
|
||||||
|
|
||||||
#define CALL_PRINTF(fmt_func, ctx, out, fmt) \
|
|
||||||
va_list args; \
|
|
||||||
va_start(args, fmt); \
|
|
||||||
int result = fmt_func(ctx, out, fmt, args); \
|
|
||||||
va_end(args)
|
|
||||||
|
|
||||||
enum ArgLength {
|
|
||||||
LEN_HH,
|
|
||||||
LEN_H,
|
|
||||||
LEN_I,
|
|
||||||
LEN_L,
|
|
||||||
LEN_LL,
|
|
||||||
LEN_J,
|
|
||||||
LEN_Z,
|
|
||||||
LEN_T,
|
|
||||||
} typedef ArgLength;
|
|
||||||
|
|
||||||
enum ArgConv {
|
|
||||||
CONV_INT,
|
|
||||||
CONV_FLT,
|
|
||||||
CONV_EXP,
|
|
||||||
CONV_SCI,
|
|
||||||
CONV_CHAR,
|
|
||||||
CONV_STR,
|
|
||||||
CONV_PTR,
|
|
||||||
CONV_N,
|
|
||||||
CONV_PERCENT,
|
|
||||||
} typedef ArgConv;
|
|
||||||
|
|
||||||
struct Format typedef Format;
|
|
||||||
struct Format {
|
|
||||||
bool flag_left;
|
|
||||||
bool flag_sign;
|
|
||||||
bool flag_space;
|
|
||||||
bool flag_form;
|
|
||||||
bool flag_zero;
|
|
||||||
bool flag_upper;
|
|
||||||
bool flag_unsigned;
|
|
||||||
int base;
|
|
||||||
int width;
|
|
||||||
int prec;
|
|
||||||
ArgLength arg_len;
|
|
||||||
ArgConv arg_conv;
|
|
||||||
};
|
|
||||||
|
|
||||||
inline static uint64_t get_int_arg(
|
|
||||||
Format *fmt,
|
|
||||||
va_list *args,
|
|
||||||
bool *signp
|
|
||||||
) {
|
|
||||||
bool sign = 0;
|
|
||||||
uint64_t num = 0;
|
|
||||||
|
|
||||||
// Read the integer from the args and split it into tuple of (sign, digits)
|
|
||||||
// If we've got HH or H we need to parse as int, and do the necessary conv
|
|
||||||
// to unsigned if needed.
|
|
||||||
if(fmt->arg_len < LEN_I) {
|
|
||||||
int ch = va_arg(*args, int);
|
|
||||||
if(ch < 0) {
|
|
||||||
if(fmt->flag_unsigned) {
|
|
||||||
num = ch + (fmt->arg_len == LEN_HH? UCHAR_MAX : USHRT_MAX);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
num = -ch;
|
|
||||||
sign = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Otherwise we see whether the number is signed or unsigned. For unsigned
|
|
||||||
// numbers we just parse according to the length, for signed we do that
|
|
||||||
// plus handle the sign
|
|
||||||
else if(fmt->flag_unsigned) {
|
|
||||||
switch(fmt->arg_len) {
|
|
||||||
case LEN_I: num = va_arg(*args, unsigned int); break;
|
|
||||||
case LEN_L: num = va_arg(*args, unsigned long); break;
|
|
||||||
case LEN_LL: num = va_arg(*args, unsigned long long); break;
|
|
||||||
case LEN_J: num = va_arg(*args, uintmax_t); break;
|
|
||||||
case LEN_Z: num = va_arg(*args, size_t); break;
|
|
||||||
case LEN_T: num = va_arg(*args, size_t); break;
|
|
||||||
default:;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// TODO: signed size_t
|
|
||||||
int64_t i = 0;
|
|
||||||
switch(fmt->arg_len) {
|
|
||||||
case LEN_I: i = va_arg(*args, int); break;
|
|
||||||
case LEN_L: i = va_arg(*args, long); break;
|
|
||||||
case LEN_LL: i = va_arg(*args, long long); break;
|
|
||||||
case LEN_J: i = va_arg(*args, uintmax_t); break;
|
|
||||||
case LEN_Z: i = va_arg(*args, int64_t); break;
|
|
||||||
case LEN_T: i = va_arg(*args, ptrdiff_t); break;
|
|
||||||
default:;
|
|
||||||
}
|
|
||||||
if(i < 0) {
|
|
||||||
num = -i;
|
|
||||||
sign = 1;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
num = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
*signp = sign;
|
|
||||||
return num;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Generic printf function that is used to print to stdout, strings and files.
|
|
||||||
// The basic idea is to make generic printf that uses output function as
|
|
||||||
// parameter and that function is distinct for printing to files, strings etc.
|
|
||||||
// Furthermore, this generic printf is abbstracted over character type, and
|
|
||||||
// depending on the macro fchar it could print in char's or wchar_t's.
|
|
||||||
|
|
||||||
typedef void (suffix(out_func_t))(void* ctx, fchar ch);
|
|
||||||
|
|
||||||
inline static int suffix(fmt_atoi)(fchar const *str, int *value) {
|
|
||||||
int i = 0;
|
|
||||||
int val = 0;
|
|
||||||
while('0' <= str[i] && str[i] <= '9') {
|
|
||||||
int digit = str[i] - '0';
|
|
||||||
if(val > (INT_MAX - digit) / 10) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
val = 10*val + digit;
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
*value = val;
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline static int suffix(fmt_parse)(
|
|
||||||
Format *format,
|
|
||||||
fchar const *str,
|
|
||||||
va_list *args
|
|
||||||
) {
|
|
||||||
*format = (Format){0};
|
|
||||||
// Parse flags
|
|
||||||
int i = 0;
|
|
||||||
for(;;) {
|
|
||||||
if (str[i] == '-') format->flag_left = true;
|
|
||||||
else if(str[i] == '+') format->flag_sign = true;
|
|
||||||
else if(str[i] == ' ') format->flag_space = true;
|
|
||||||
else if(str[i] == '#') format->flag_form = true;
|
|
||||||
else if(str[i] == '0') format->flag_zero = true;
|
|
||||||
else break;
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
// Optional width specifier
|
|
||||||
int width = 0;
|
|
||||||
if(str[i] == '*') {
|
|
||||||
++i;
|
|
||||||
width = va_arg(*args, int);
|
|
||||||
if(width < 0) {
|
|
||||||
width = -width;
|
|
||||||
format->flag_zero = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
int width_len = suffix(fmt_atoi)(str+i, &width);
|
|
||||||
if(width_len < 0) return -1;
|
|
||||||
i += width_len;
|
|
||||||
}
|
|
||||||
// Optional precision specifier
|
|
||||||
int prec = 0;
|
|
||||||
if(str[i] == '.') {
|
|
||||||
++i;
|
|
||||||
if(str[i] == '*') {
|
|
||||||
++i;
|
|
||||||
prec = va_arg(*args, int);
|
|
||||||
if(prec < 0) {
|
|
||||||
prec = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
int prec_len = suffix(fmt_atoi)(str+i, &prec);
|
|
||||||
if(prec_len < 0) return -1;
|
|
||||||
i += prec_len;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
format->width = width;
|
|
||||||
format->prec = prec;
|
|
||||||
// Optional length modifier
|
|
||||||
format->arg_len = LEN_I;
|
|
||||||
if(str[i] == 'h') {
|
|
||||||
++i;
|
|
||||||
format->arg_len = LEN_H;
|
|
||||||
if(str[i] == 'h') {
|
|
||||||
++i;
|
|
||||||
format->arg_len = LEN_HH;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if(str[i] == 'l') {
|
|
||||||
++i;
|
|
||||||
format->arg_len = LEN_L;
|
|
||||||
if(str[i] == 'l') {
|
|
||||||
++i;
|
|
||||||
format->arg_len = LEN_LL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if(str[i] == 'j') {
|
|
||||||
++i;
|
|
||||||
format->arg_len = LEN_J;
|
|
||||||
}
|
|
||||||
else if(str[i] == 'z') {
|
|
||||||
++i;
|
|
||||||
format->arg_len = LEN_Z;
|
|
||||||
}
|
|
||||||
else if(str[i] == 't') {
|
|
||||||
++i;
|
|
||||||
format->arg_len = LEN_T;
|
|
||||||
}
|
|
||||||
else if(str[i] == 'L') {
|
|
||||||
++i;
|
|
||||||
format->arg_len = LEN_L;
|
|
||||||
}
|
|
||||||
// Conversion specifier
|
|
||||||
switch(str[i]) {
|
|
||||||
case 'd':
|
|
||||||
case 'i':
|
|
||||||
format->arg_conv = CONV_INT;
|
|
||||||
format->base = 10;
|
|
||||||
break;
|
|
||||||
case 'u':
|
|
||||||
format->arg_conv = CONV_INT;
|
|
||||||
format->flag_unsigned = true;
|
|
||||||
format->base = 10;
|
|
||||||
break;
|
|
||||||
case 'o':
|
|
||||||
format->arg_conv = CONV_INT;
|
|
||||||
format->flag_unsigned = true;
|
|
||||||
format->base = 8;
|
|
||||||
break;
|
|
||||||
case 'x':
|
|
||||||
format->arg_conv = CONV_INT;
|
|
||||||
format->flag_unsigned = true;
|
|
||||||
format->base = 16;
|
|
||||||
break;
|
|
||||||
case 'X':
|
|
||||||
format->arg_conv = CONV_INT;
|
|
||||||
format->flag_unsigned = true;
|
|
||||||
format->flag_upper = true;
|
|
||||||
format->base = 16;
|
|
||||||
break;
|
|
||||||
case 'f':
|
|
||||||
format->arg_conv = CONV_FLT;
|
|
||||||
format->base = 10;
|
|
||||||
break;
|
|
||||||
case 'F':
|
|
||||||
format->arg_conv = CONV_FLT;
|
|
||||||
format->flag_upper = true;
|
|
||||||
format->base = 10;
|
|
||||||
break;
|
|
||||||
case 'e':
|
|
||||||
format->arg_conv = CONV_EXP;
|
|
||||||
format->base = 10;
|
|
||||||
break;
|
|
||||||
case 'E':
|
|
||||||
format->arg_conv = CONV_EXP;
|
|
||||||
format->flag_upper = true;
|
|
||||||
format->base = 10;
|
|
||||||
break;
|
|
||||||
case 'g':
|
|
||||||
format->arg_conv = CONV_SCI;
|
|
||||||
format->base = 10;
|
|
||||||
break;
|
|
||||||
case 'G':
|
|
||||||
format->arg_conv = CONV_SCI;
|
|
||||||
format->flag_upper = true;
|
|
||||||
format->base = 10;
|
|
||||||
break;
|
|
||||||
case 'a':
|
|
||||||
format->arg_conv = CONV_FLT;
|
|
||||||
format->base = 16;
|
|
||||||
break;
|
|
||||||
case 'A':
|
|
||||||
format->arg_conv = CONV_FLT;
|
|
||||||
format->flag_upper = true;
|
|
||||||
format->base = 16;
|
|
||||||
break;
|
|
||||||
case 'c':
|
|
||||||
format->arg_conv = CONV_CHAR;
|
|
||||||
break;
|
|
||||||
case 's':
|
|
||||||
format->arg_conv = CONV_STR;
|
|
||||||
break;
|
|
||||||
case 'p':
|
|
||||||
format->arg_conv = CONV_PTR;
|
|
||||||
break;
|
|
||||||
case 'n':
|
|
||||||
format->arg_conv = CONV_N;
|
|
||||||
break;
|
|
||||||
case '%':
|
|
||||||
format->arg_conv = CONV_PERCENT;
|
|
||||||
break;
|
|
||||||
default: return -1;
|
|
||||||
}
|
|
||||||
++i;
|
|
||||||
// Ignoring flags etc
|
|
||||||
if(format->flag_sign && format->flag_zero) {
|
|
||||||
format->flag_zero = 0;
|
|
||||||
}
|
|
||||||
if(format->flag_sign && format->flag_space) {
|
|
||||||
format->flag_space = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(format->prec != 0) {
|
|
||||||
format->flag_zero = 0;
|
|
||||||
}
|
|
||||||
else if(format->flag_zero) {
|
|
||||||
// HACK: NOTE: I hate printf formats
|
|
||||||
format->prec = format->width;
|
|
||||||
format->width = 0;
|
|
||||||
}
|
|
||||||
if(format->arg_conv == CONV_FLT && format->prec == 0) {
|
|
||||||
format->prec = 6;
|
|
||||||
}
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline static int suffix(fmt_fprint_int)(
|
|
||||||
void *ctx,
|
|
||||||
suffix(out_func_t) *out,
|
|
||||||
Format *fmt,
|
|
||||||
va_list *args
|
|
||||||
) {
|
|
||||||
int w = 0;
|
|
||||||
|
|
||||||
bool sign;
|
|
||||||
uint64_t num = get_int_arg(fmt, args, &sign);
|
|
||||||
|
|
||||||
// Find the actual length the number takes up
|
|
||||||
int prefix_len = 0;
|
|
||||||
int digits_num = 0;
|
|
||||||
if(fmt->flag_space || fmt->flag_sign || sign) {
|
|
||||||
prefix_len = 1;
|
|
||||||
}
|
|
||||||
if(num != 0 && fmt->flag_form) {
|
|
||||||
if(fmt->base == 16) prefix_len += 2; // 0x
|
|
||||||
if(fmt->base == 8) digits_num += 1; // 0
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
uint64_t digits = num;
|
|
||||||
do {
|
|
||||||
digits_num += 1;
|
|
||||||
digits /= fmt->base;
|
|
||||||
} while(digits != 0);
|
|
||||||
}
|
|
||||||
int s_len = prefix_len + digits_num; // length of significant chars
|
|
||||||
int d_len = s_len; // length of all displayed chars
|
|
||||||
int zpad = 0; // pre-pad of zeroes from precision
|
|
||||||
if(digits_num < fmt->prec) {
|
|
||||||
zpad = fmt->prec - digits_num;
|
|
||||||
d_len = s_len + zpad;
|
|
||||||
}
|
|
||||||
|
|
||||||
// See if padding is necessary and extract info about padding
|
|
||||||
bool left_pad = false;
|
|
||||||
bool right_pad = true;
|
|
||||||
char pad_ch = ' ';
|
|
||||||
int pad_len = 0;
|
|
||||||
if(!sign && fmt->flag_space) { // make space part of pad
|
|
||||||
d_len += 1;
|
|
||||||
pad_len = 1;
|
|
||||||
}
|
|
||||||
if(d_len < fmt->width) {
|
|
||||||
pad_len = fmt->width - d_len;
|
|
||||||
}
|
|
||||||
if(fmt->flag_left) {
|
|
||||||
left_pad = true;
|
|
||||||
right_pad = false;
|
|
||||||
}
|
|
||||||
if(fmt->flag_zero) {
|
|
||||||
pad_ch = '0';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fill up an array of significant digits
|
|
||||||
char digits_arr[33] = {0};
|
|
||||||
char *digits = digits_arr + countof(digits_arr);
|
|
||||||
{
|
|
||||||
uint64_t temp = num;
|
|
||||||
do {
|
|
||||||
int digit = temp % fmt->base;
|
|
||||||
char ch = 0;
|
|
||||||
if(digit < 10) ch = digit + '0';
|
|
||||||
else if(fmt->flag_upper) ch = digit - 10 + 'A';
|
|
||||||
else ch = digit - 10 + 'a';
|
|
||||||
*--digits = ch;
|
|
||||||
temp /= fmt->base;
|
|
||||||
} while(temp != 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start displaying number
|
|
||||||
// Left-pad if necessary
|
|
||||||
if(left_pad) while(pad_len--) {
|
|
||||||
out(ctx, pad_ch);
|
|
||||||
++w;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Print sign
|
|
||||||
if(sign) { out(ctx, '-'); ++w; }
|
|
||||||
else if(fmt->flag_sign) { out(ctx, '+'); ++w; }
|
|
||||||
else if(fmt->flag_space) { out(ctx, ' '); ++w; }
|
|
||||||
|
|
||||||
// Print 0x, 0X
|
|
||||||
if(num != 0 && fmt->base == 16 && fmt->flag_form) {
|
|
||||||
out(ctx, '0');
|
|
||||||
if(fmt->flag_upper) out(ctx, 'X');
|
|
||||||
else out(ctx, 'x');
|
|
||||||
w += 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Print zpad
|
|
||||||
while(zpad--) {
|
|
||||||
out(ctx, '0');
|
|
||||||
++ w;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Print digit string
|
|
||||||
while(*digits != 0) {
|
|
||||||
out(ctx, *digits);
|
|
||||||
++digits;
|
|
||||||
++w;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Right-pad if necessary
|
|
||||||
if(right_pad) while(pad_len--) {
|
|
||||||
out(ctx, pad_ch);
|
|
||||||
++w;
|
|
||||||
}
|
|
||||||
|
|
||||||
return w;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline static int suffix(fmt_fprint_ptr)(
|
|
||||||
void *ctx,
|
|
||||||
suffix(out_func_t) *out,
|
|
||||||
Format *fmt,
|
|
||||||
va_list *args
|
|
||||||
) {
|
|
||||||
int w = 0;
|
|
||||||
uintptr_t num = va_arg(*args, uintptr_t);
|
|
||||||
|
|
||||||
int s_len = 2 + 16; // length of significant chars
|
|
||||||
int d_len = s_len; // length of all displayed chars
|
|
||||||
int zpad = 0; // pre-pad of zeroes from precision
|
|
||||||
if(16 < fmt->prec) {
|
|
||||||
zpad = fmt->prec - 16;
|
|
||||||
d_len = s_len + zpad;
|
|
||||||
}
|
|
||||||
|
|
||||||
// See if padding is necessary and extract info about padding
|
|
||||||
bool left_pad = true;
|
|
||||||
bool right_pad = false;
|
|
||||||
char pad_ch = ' ';
|
|
||||||
int pad_len = 0;
|
|
||||||
if(d_len < fmt->width) {
|
|
||||||
pad_len = fmt->width - d_len;
|
|
||||||
}
|
|
||||||
if(fmt->flag_left) {
|
|
||||||
left_pad = false;
|
|
||||||
right_pad = true;
|
|
||||||
}
|
|
||||||
if(fmt->flag_zero) {
|
|
||||||
pad_ch = '0';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fill up an array of significant digits
|
|
||||||
char digits_arr[33] = {0};
|
|
||||||
char *digits = digits_arr + countof(digits_arr);
|
|
||||||
{
|
|
||||||
uint64_t temp = num;
|
|
||||||
do {
|
|
||||||
int digit = temp % 16;
|
|
||||||
char ch = 0;
|
|
||||||
if(digit < 10) ch = digit + '0';
|
|
||||||
else if(fmt->flag_upper) ch = digit - 10 + 'A';
|
|
||||||
else ch = digit - 10 + 'a';
|
|
||||||
*--digits = ch;
|
|
||||||
temp /= 16;
|
|
||||||
} while(s_len-- != 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start displaying number
|
|
||||||
// Left-pad if necessary
|
|
||||||
if(left_pad) while(pad_len--) {
|
|
||||||
out(ctx, pad_ch);
|
|
||||||
++w;
|
|
||||||
}
|
|
||||||
|
|
||||||
out(ctx, '0');
|
|
||||||
out(ctx, 'x');
|
|
||||||
w += 2;
|
|
||||||
|
|
||||||
// Print zpad
|
|
||||||
while(zpad--) {
|
|
||||||
out(ctx, '0');
|
|
||||||
++ w;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Print digit string
|
|
||||||
while(*digits != 0) {
|
|
||||||
out(ctx, *digits);
|
|
||||||
++digits;
|
|
||||||
++w;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Right-pad if necessary
|
|
||||||
if(right_pad) while(pad_len--) {
|
|
||||||
out(ctx, pad_ch);
|
|
||||||
++w;
|
|
||||||
}
|
|
||||||
|
|
||||||
return w;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline static int suffix(fmt_fprint_char)(
|
|
||||||
void *ctx,
|
|
||||||
suffix(out_func_t) *out,
|
|
||||||
Format *fmt,
|
|
||||||
va_list *args
|
|
||||||
) {
|
|
||||||
int w = 0;
|
|
||||||
bool sign;
|
|
||||||
uint64_t num = get_int_arg(fmt, args, &sign);
|
|
||||||
|
|
||||||
// Calculate padding
|
|
||||||
bool left_pad = true;
|
|
||||||
bool right_pad = false;
|
|
||||||
uint64_t pad = 0;
|
|
||||||
if(1 < fmt->width) {
|
|
||||||
pad = fmt->width - 1;
|
|
||||||
}
|
|
||||||
if(fmt->flag_left) {
|
|
||||||
left_pad = false;
|
|
||||||
right_pad = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Print left pad
|
|
||||||
if(left_pad) while(pad--) {
|
|
||||||
out(ctx, ' ');
|
|
||||||
++w;
|
|
||||||
}
|
|
||||||
|
|
||||||
out(ctx, num);
|
|
||||||
++w;
|
|
||||||
|
|
||||||
// Print right pad
|
|
||||||
if(right_pad) while(pad--) {
|
|
||||||
out(ctx, ' ');
|
|
||||||
++w;
|
|
||||||
}
|
|
||||||
|
|
||||||
return w;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline static int suffix(fmt_just_fucking_print_float_someone_improve_this_later)(
|
|
||||||
void *ctx,
|
|
||||||
suffix(out_func_t) *out,
|
|
||||||
Format *fmt,
|
|
||||||
va_list *args
|
|
||||||
) {
|
|
||||||
int w = 0;
|
|
||||||
double f = va_arg(*args, double);
|
|
||||||
uint64_t i = (uint64_t)f;
|
|
||||||
|
|
||||||
char digits_arr[33] = {0};
|
|
||||||
char *digits = digits_arr + countof(digits_arr);
|
|
||||||
{
|
|
||||||
uint64_t t = i;
|
|
||||||
do {
|
|
||||||
char ch = (t % 10) + '0';
|
|
||||||
*--digits = ch;
|
|
||||||
t /= 10;
|
|
||||||
} while(t-- != 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
while(*digits != 0) {
|
|
||||||
out(ctx, *digits);
|
|
||||||
++digits;
|
|
||||||
++w;
|
|
||||||
}
|
|
||||||
|
|
||||||
f -= i;
|
|
||||||
uint64_t nprec = fmt->prec;
|
|
||||||
if(nprec != 0) {
|
|
||||||
out(ctx, '.');
|
|
||||||
w++;
|
|
||||||
}
|
|
||||||
|
|
||||||
for(int i = 0; i != fmt->prec; ++i) {
|
|
||||||
f *= 10;
|
|
||||||
uint64_t digit = (uint64_t)f;
|
|
||||||
out(ctx, digit + '0');
|
|
||||||
++w;
|
|
||||||
f -= digit;
|
|
||||||
}
|
|
||||||
|
|
||||||
return w;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline static int suffix(fmt_fprint_str)(
|
|
||||||
void *ctx,
|
|
||||||
suffix(out_func_t) *out,
|
|
||||||
Format *fmt,
|
|
||||||
va_list *args
|
|
||||||
) {
|
|
||||||
int w = 0;
|
|
||||||
char *str = va_arg(*args, char *);
|
|
||||||
uint64_t len = strlen(str);
|
|
||||||
|
|
||||||
// Calculate padding
|
|
||||||
bool left_pad = true;
|
|
||||||
bool right_pad = false;
|
|
||||||
uint64_t pad = 0;
|
|
||||||
if(len < fmt->width) {
|
|
||||||
pad = fmt->width - len;
|
|
||||||
}
|
|
||||||
if(fmt->flag_left) {
|
|
||||||
left_pad = false;
|
|
||||||
right_pad = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Print left pad
|
|
||||||
if(left_pad) while(pad--) {
|
|
||||||
out(ctx, ' ');
|
|
||||||
++w;
|
|
||||||
}
|
|
||||||
|
|
||||||
while(*str) {
|
|
||||||
out(ctx, *str++);
|
|
||||||
++w;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Print right pad
|
|
||||||
if(right_pad) while(pad--) {
|
|
||||||
out(ctx, ' ');
|
|
||||||
++w;
|
|
||||||
}
|
|
||||||
|
|
||||||
return w;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline static int suffix(fmt_print)(
|
|
||||||
void *ctx,
|
|
||||||
suffix(out_func_t) *out,
|
|
||||||
const fchar *fmt,
|
|
||||||
va_list args
|
|
||||||
) {
|
|
||||||
int w = 0; // N chars output
|
|
||||||
int i = 0; // N chars read from fmt
|
|
||||||
while(fmt[i] != 0) {
|
|
||||||
if(fmt[i] == '%') {
|
|
||||||
++i;
|
|
||||||
Format format;
|
|
||||||
int fmt_len = suffix(fmt_parse)(&format, fmt+i, &args);
|
|
||||||
if(fmt_len < 0) return -1;
|
|
||||||
i += fmt_len;
|
|
||||||
int written;
|
|
||||||
switch(format.arg_conv) {
|
|
||||||
case CONV_INT: {
|
|
||||||
written = suffix(fmt_fprint_int)(ctx, out, &format, &args);
|
|
||||||
} break;
|
|
||||||
case CONV_FLT: {
|
|
||||||
written = suffix(fmt_just_fucking_print_float_someone_improve_this_later)(ctx, out, &format, &args);
|
|
||||||
} break;
|
|
||||||
case CONV_EXP: {
|
|
||||||
written = suffix(fmt_just_fucking_print_float_someone_improve_this_later)(ctx, out, &format, &args);
|
|
||||||
} break;
|
|
||||||
case CONV_SCI: {
|
|
||||||
written = suffix(fmt_just_fucking_print_float_someone_improve_this_later)(ctx, out, &format, &args);
|
|
||||||
} break;
|
|
||||||
case CONV_CHAR: {
|
|
||||||
written = suffix(fmt_fprint_char)(ctx, out, &format, &args);
|
|
||||||
} break;
|
|
||||||
case CONV_STR: {
|
|
||||||
written = suffix(fmt_fprint_str)(ctx, out, &format, &args);
|
|
||||||
} break;
|
|
||||||
case CONV_PTR: {
|
|
||||||
written = suffix(fmt_fprint_ptr)(ctx, out, &format, &args);
|
|
||||||
} break;
|
|
||||||
case CONV_N: {
|
|
||||||
int *n = va_arg(args, int *);
|
|
||||||
*n = w;
|
|
||||||
written = 0;
|
|
||||||
} break;
|
|
||||||
case CONV_PERCENT: {
|
|
||||||
out(ctx, '%');
|
|
||||||
written = 1;
|
|
||||||
} break;
|
|
||||||
if(written < 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
w += written;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Print non-formatted characters as god intended
|
|
||||||
else while(fmt[i] != '%' && fmt[i] != 0) {
|
|
||||||
out(ctx, fmt[i]);
|
|
||||||
++i;
|
|
||||||
++w;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,67 +0,0 @@
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <ctype.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <math.h>
|
|
||||||
|
|
||||||
#include <_os.h>
|
|
||||||
|
|
||||||
#define __STDC_WANT_LIB_EXT1__ 1
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
// Instantiate generic printf function for byte strings
|
|
||||||
// TODO: instantiate wide char variants of print
|
|
||||||
#define suffix(name) name ## _char
|
|
||||||
#define fchar char
|
|
||||||
#define fstrlen(s, maxsize) strnlen_s(s, maxsize)
|
|
||||||
#include "fmt_print.h"
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
size_t used, capacity;
|
|
||||||
char* string;
|
|
||||||
} StrPrintCtx;
|
|
||||||
|
|
||||||
static void string_write(void *ctx, char ch) {
|
|
||||||
StrPrintCtx *c = ctx;
|
|
||||||
c->string[c->used++] = ch;
|
|
||||||
}
|
|
||||||
|
|
||||||
int fprintf(FILE *file, const char *restrict fmt, ...) {
|
|
||||||
CALL_PRINTF(fmt_print_char, file, _os_file_write_char, fmt);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
int printf(const char *restrict fmt, ...) {
|
|
||||||
CALL_PRINTF(fmt_print_char, stdout, _os_file_write_char, fmt);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
int snprintf(char *restrict s, size_t n, const char *restrict fmt, ...) {
|
|
||||||
StrPrintCtx ctx = { 0, n, s };
|
|
||||||
CALL_PRINTF(fmt_print_char, &ctx, string_write, fmt);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
int sprintf(char *restrict s, const char *restrict fmt, ...) {
|
|
||||||
StrPrintCtx ctx = { 0, SIZE_MAX, s };
|
|
||||||
CALL_PRINTF(fmt_print_char, &ctx, string_write, fmt);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
int vfprintf(FILE *file, const char *restrict fmt, va_list args) {
|
|
||||||
return fmt_print_char(file, _os_file_write_char, fmt, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
int vprintf(const char *restrict fmt, va_list args) {
|
|
||||||
return fmt_print_char(stdout, _os_file_write_char, fmt, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
int vsnprintf(char *restrict s, size_t n, const char *restrict fmt, va_list args) {
|
|
||||||
StrPrintCtx ctx = { 0, n, s };
|
|
||||||
return fmt_print_char(&ctx, string_write, fmt, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
int vsprintf(char *restrict s, const char *restrict fmt, va_list args) {
|
|
||||||
StrPrintCtx ctx = { 0, SIZE_MAX, s };
|
|
||||||
return fmt_print_char(&ctx, string_write, fmt, args);
|
|
||||||
}
|
|
|
@ -1,40 +0,0 @@
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <signal.h>
|
|
||||||
|
|
||||||
#include <_os.h>
|
|
||||||
|
|
||||||
typedef void (*ExitRoutine)(void);
|
|
||||||
|
|
||||||
// The implementation shall support the registration
|
|
||||||
// of at least 32 functions.
|
|
||||||
static ExitRoutine _exit_routines[64];
|
|
||||||
static int _exit_routine_count;
|
|
||||||
|
|
||||||
_Noreturn void abort(void) {
|
|
||||||
raise(SIGABRT);
|
|
||||||
_os_exit(-69);
|
|
||||||
}
|
|
||||||
|
|
||||||
int atexit(void (*func)(void)) {
|
|
||||||
if (_exit_routine_count >= COUNTOF(_exit_routines)) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
_exit_routines[_exit_routine_count++] = func;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
_Noreturn void exit(int status) {
|
|
||||||
// doing them in reverse seems nicer
|
|
||||||
for (int i = _exit_routine_count; i--;) {
|
|
||||||
_exit_routines[i]();
|
|
||||||
}
|
|
||||||
|
|
||||||
_os_exit(status);
|
|
||||||
}
|
|
||||||
|
|
||||||
_Noreturn void _Exit(int status) {
|
|
||||||
// doesn't run atexit routines
|
|
||||||
_os_exit(status);
|
|
||||||
}
|
|
|
@ -1,13 +1,12 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <_os.h>
|
|
||||||
|
|
||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
|
#include <processenv.h>
|
||||||
|
#include <shellapi.h>
|
||||||
|
#include <DbgHelp.h>
|
||||||
|
|
||||||
struct _os_heap {
|
void _setup_timer(void);
|
||||||
HANDLE handle;
|
void _setup_eh();
|
||||||
};
|
void _setup_heap();
|
||||||
|
|
||||||
void _os_timing_init(void);
|
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include <win.h>
|
||||||
|
//#include <stdio.h> // printf
|
||||||
|
#include <stdlib.h> // abort
|
||||||
|
|
||||||
|
void _Noreturn _assert(
|
||||||
|
char const *cond,
|
||||||
|
char const *func,
|
||||||
|
char const *file,
|
||||||
|
int line
|
||||||
|
) {
|
||||||
|
// printf("Assertion failed: %s\n", cond);
|
||||||
|
// printf(" Function: %s\n", func);
|
||||||
|
// printf(" File: %s\n", file);
|
||||||
|
// printf(" Line: %d\n", line);
|
||||||
|
// printf("Trace:\n");
|
||||||
|
// _os_print_stack_trace();
|
||||||
|
abort();
|
||||||
|
}
|
|
@ -1,96 +0,0 @@
|
||||||
|
|
||||||
#include <_os.h>
|
|
||||||
|
|
||||||
#include <locale.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#include "win.h"
|
|
||||||
|
|
||||||
extern int main(int argc, char** argv);
|
|
||||||
|
|
||||||
// Some shell32.lib related crap
|
|
||||||
DECLSPEC_IMPORT LPWSTR GetCommandLineW();
|
|
||||||
DECLSPEC_IMPORT LPWSTR* CommandLineToArgvW(LPCWSTR lpCmdLine, int* pNumArgs);
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t count_wide_chars(const wchar_t* str) {
|
|
||||||
size_t len = 0;
|
|
||||||
while (str[len] != 0) len++;
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool convert_wide_chars_to_ansi(char* out, const wchar_t* str, size_t len) {
|
|
||||||
for (size_t i = 0; i < len; i++) {
|
|
||||||
wchar_t ch = *str++;
|
|
||||||
if (ch < 0 || 0x7F >= ch) {
|
|
||||||
*out++ = 0;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
*out++ = ch;
|
|
||||||
}
|
|
||||||
|
|
||||||
*out++ = 0;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void mainCRTStartup() {
|
|
||||||
_os_timing_init();
|
|
||||||
|
|
||||||
HANDLE heap = GetProcessHeap();
|
|
||||||
if (heap == NULL) {
|
|
||||||
ExitProcess(-42069);
|
|
||||||
}
|
|
||||||
|
|
||||||
int arg_count;
|
|
||||||
LPWSTR* args_wide = CommandLineToArgvW(GetCommandLineW(), &arg_count);
|
|
||||||
if (!args_wide) {
|
|
||||||
ExitProcess(-69420);
|
|
||||||
}
|
|
||||||
|
|
||||||
char** args = HeapAlloc(heap, 0, arg_count * sizeof(char*));
|
|
||||||
if (arg_count == 0) {
|
|
||||||
arg_count = 1;
|
|
||||||
args[0] = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert wide chars into ANSI
|
|
||||||
for (int i = 0; i < arg_count; i++) {
|
|
||||||
size_t wide_len = count_wide_chars(args_wide[i]) + 1;
|
|
||||||
args[i] = HeapAlloc(heap, 0, wide_len);
|
|
||||||
|
|
||||||
convert_wide_chars_to_ansi(args[i], args_wide[i], wide_len);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize terminal
|
|
||||||
stdout = (FILE*) GetStdHandle(STD_OUTPUT_HANDLE);
|
|
||||||
stderr = (FILE*) GetStdHandle(STD_ERROR_HANDLE);
|
|
||||||
stdin = (FILE*) GetStdHandle(STD_INPUT_HANDLE);
|
|
||||||
|
|
||||||
// Initialize heap
|
|
||||||
_os_heap heap_data = {
|
|
||||||
.handle = heap,
|
|
||||||
};
|
|
||||||
_heap_setup(&heap_data);
|
|
||||||
|
|
||||||
srand(0);
|
|
||||||
setlocale(LC_ALL, "C");
|
|
||||||
_os_init_eh();
|
|
||||||
|
|
||||||
int exit_code = main(arg_count, args);
|
|
||||||
|
|
||||||
// we call exit because we want atexit routines run
|
|
||||||
exit(exit_code);
|
|
||||||
}
|
|
||||||
|
|
||||||
// This symbol is required to be present if we're using floating-point
|
|
||||||
// numbers
|
|
||||||
int _fltused=0;
|
|
|
@ -1,35 +0,0 @@
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#include "win.h"
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
_Noreturn void _os_exit(int code) {
|
|
||||||
ExitProcess(code);
|
|
||||||
}
|
|
|
@ -0,0 +1,147 @@
|
||||||
|
|
||||||
|
#include <locale.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
|
#include <win.h>
|
||||||
|
|
||||||
|
// Windows symbols because windows
|
||||||
|
int _fltused=0;
|
||||||
|
|
||||||
|
extern int main(int argc, char** argv);
|
||||||
|
|
||||||
|
// Exit routines
|
||||||
|
#define ATEXIT_FUNC_COUNT 64
|
||||||
|
static void (*atexit_funcs[ATEXIT_FUNC_COUNT])(void);
|
||||||
|
static int atexit_func_count;
|
||||||
|
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t count_wide_chars(const wchar_t* str) {
|
||||||
|
size_t len = 0;
|
||||||
|
while (str[len] != 0) len++;
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool wchar_to_ansi(char* out, const wchar_t* str, size_t len) {
|
||||||
|
for (size_t i = 0; i < len; i++) {
|
||||||
|
wchar_t ch = *str++;
|
||||||
|
if (ch < 0 || ch > 0x7F) {
|
||||||
|
*out++ = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*out++ = ch;
|
||||||
|
}
|
||||||
|
|
||||||
|
*out++ = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char **get_command_args(int *argc_ptr) {
|
||||||
|
int argc;
|
||||||
|
char** args;
|
||||||
|
|
||||||
|
LPCWSTR command_line = GetCommandLineW();
|
||||||
|
LPWSTR* args_wide = CommandLineToArgvW(command_line, &argc);
|
||||||
|
if (!args_wide || argc <= 0) {
|
||||||
|
ExitProcess(-69420);
|
||||||
|
}
|
||||||
|
|
||||||
|
args = calloc(argc, sizeof(char*));
|
||||||
|
|
||||||
|
// Convert wide chars into ANSI
|
||||||
|
for (int i = 0; i < argc; i++) {
|
||||||
|
size_t arg_len = count_wide_chars(args_wide[i]);
|
||||||
|
args[i] = malloc(arg_len+1);
|
||||||
|
wchar_to_ansi(args[i], args_wide[i], arg_len+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
*argc_ptr = argc;
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void mainCRTStartup() {
|
||||||
|
// Initialize standard pipe handles
|
||||||
|
stdout = (FILE*) GetStdHandle(STD_OUTPUT_HANDLE);
|
||||||
|
stderr = (FILE*) GetStdHandle(STD_ERROR_HANDLE);
|
||||||
|
stdin = (FILE*) GetStdHandle(STD_INPUT_HANDLE);
|
||||||
|
|
||||||
|
// Set-up some platform stuff
|
||||||
|
_setup_heap();
|
||||||
|
_setup_eh();
|
||||||
|
_setup_timer();
|
||||||
|
|
||||||
|
// Set-up CRT stuff
|
||||||
|
srand(0);
|
||||||
|
setlocale(LC_ALL, "C");
|
||||||
|
|
||||||
|
// Parse command-line arguments
|
||||||
|
int argc;
|
||||||
|
char **args = get_command_args(&argc);
|
||||||
|
int exit_code = main(argc, args);
|
||||||
|
|
||||||
|
// we call exit because we want atexit routines run
|
||||||
|
exit(exit_code);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
_Noreturn void abort(void) {
|
||||||
|
raise(SIGABRT);
|
||||||
|
ExitProcess(-69);
|
||||||
|
}
|
||||||
|
|
||||||
|
int atexit(void (*func)(void)) {
|
||||||
|
if (atexit_func_count >= ATEXIT_FUNC_COUNT) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
atexit_funcs[atexit_func_count++] = func;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
_Noreturn void exit(int status) {
|
||||||
|
for (int i = atexit_func_count; i--;) {
|
||||||
|
atexit_funcs[i]();
|
||||||
|
}
|
||||||
|
ExitProcess(status);
|
||||||
|
}
|
||||||
|
|
||||||
|
_Noreturn void _Exit(int status) {
|
||||||
|
ExitProcess(status);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
|
@ -1,13 +1,9 @@
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <win.h>
|
||||||
#include <limits.h>
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
#include "win.h"
|
static HANDLE heap_handle;
|
||||||
|
|
||||||
// TODO: lock the heap before allocation (?)
|
|
||||||
|
|
||||||
HANDLE _heap;
|
|
||||||
|
|
||||||
static bool is_power_of_two(size_t s) {
|
static bool is_power_of_two(size_t s) {
|
||||||
return (s & (s-1)) == 0;
|
return (s & (s-1)) == 0;
|
||||||
|
@ -17,8 +13,11 @@ static intptr_t align_forward(intptr_t p, size_t a) {
|
||||||
return (p+a-1)&~(a-1);
|
return (p+a-1)&~(a-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _heap_setup(_os_heap *heap) {
|
void _setup_heap() {
|
||||||
_heap = heap->handle;
|
heap_handle = GetProcessHeap();
|
||||||
|
if (heap_handle == NULL) {
|
||||||
|
ExitProcess(-42069);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void *aligned_alloc(size_t alignment, size_t size) {
|
void *aligned_alloc(size_t alignment, size_t size) {
|
||||||
|
@ -39,7 +38,7 @@ void *aligned_alloc(size_t alignment, size_t size) {
|
||||||
if(alignment > 8) {
|
if(alignment > 8) {
|
||||||
min_req_size += alignment;
|
min_req_size += alignment;
|
||||||
}
|
}
|
||||||
void *block_start = HeapAlloc(_heap, 0, min_req_size);
|
void *block_start = HeapAlloc(heap_handle, 0, min_req_size);
|
||||||
intptr_t block_start_i = (intptr_t)block_start;
|
intptr_t block_start_i = (intptr_t)block_start;
|
||||||
intptr_t aligned_block_start_i = align_forward(block_start_i, alignment);
|
intptr_t aligned_block_start_i = align_forward(block_start_i, alignment);
|
||||||
void *aligned_block_start = (void *)aligned_block_start_i;
|
void *aligned_block_start = (void *)aligned_block_start_i;
|
||||||
|
@ -53,7 +52,7 @@ void *calloc(size_t nmemb, size_t size) {
|
||||||
if(nmemb > SIZE_MAX/size) {
|
if(nmemb > SIZE_MAX/size) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
void *block_start = HeapAlloc(_heap, HEAP_ZERO_MEMORY, size*nmemb);
|
void *block_start = HeapAlloc(heap_handle, HEAP_ZERO_MEMORY, size*nmemb);
|
||||||
return block_start;
|
return block_start;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,7 +60,7 @@ void free(void *ptr) {
|
||||||
if(ptr == NULL) {
|
if(ptr == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
HeapFree(_heap, 0, ptr);
|
HeapFree(heap_handle, 0, ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void *malloc(size_t size) {
|
void *malloc(size_t size) {
|
||||||
|
@ -72,11 +71,12 @@ void *realloc(void *ptr, size_t size) {
|
||||||
if (ptr == NULL) {
|
if (ptr == NULL) {
|
||||||
if (size == 0) return NULL;
|
if (size == 0) return NULL;
|
||||||
|
|
||||||
return HeapAlloc(_heap, 0, size);
|
return HeapAlloc(heap_handle, 0, size);
|
||||||
} else if (size == 0) {
|
} else if (size == 0) {
|
||||||
HeapFree(_heap, 0, ptr);
|
HeapFree(heap_handle, 0, ptr);
|
||||||
return NULL;
|
return NULL;
|
||||||
} else {
|
} else {
|
||||||
return HeapReAlloc(_heap, 0, ptr, size);
|
return HeapReAlloc(heap_handle, 0, ptr, size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
134
src/win/win_io.c
134
src/win/win_io.c
|
@ -1,134 +0,0 @@
|
||||||
|
|
||||||
#include "win.h"
|
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
|
|
||||||
// It's just mapped directly to HANDLE
|
|
||||||
struct FILE {
|
|
||||||
int unused;
|
|
||||||
};
|
|
||||||
|
|
||||||
int _os_del_file(char const *filename) {
|
|
||||||
int ok = DeleteFileA(filename);
|
|
||||||
return ok != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int _os_mov_file(char const *old, char const *new) {
|
|
||||||
int ok = MoveFileA(old, new);
|
|
||||||
return ok != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *_os_tmpname(char *buffer) {
|
|
||||||
static UINT uniq = 0;
|
|
||||||
DWORD path_len = GetTempPathA(L_tmpnam, buffer);
|
|
||||||
if(path_len == 0) return NULL;
|
|
||||||
UINT ok = GetTempFileNameA(buffer, "", uniq, buffer);
|
|
||||||
if(ok == 0) return NULL;
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
FILE *_os_fopen(char const *restrict name, _OS_ModeFlags flags) {
|
|
||||||
DWORD desaddr = 0;
|
|
||||||
DWORD share = 0;
|
|
||||||
DWORD disp = 0;
|
|
||||||
switch(flags.base_mode) {
|
|
||||||
case 'r': {
|
|
||||||
desaddr = GENERIC_READ;
|
|
||||||
if(!flags.update) {
|
|
||||||
share = FILE_SHARE_READ;
|
|
||||||
}
|
|
||||||
disp = OPEN_EXISTING;
|
|
||||||
if(flags.update) {
|
|
||||||
disp = OPEN_ALWAYS;
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
case 'w': {
|
|
||||||
desaddr = GENERIC_WRITE;
|
|
||||||
disp = CREATE_ALWAYS;
|
|
||||||
} break;
|
|
||||||
case 'a': {
|
|
||||||
desaddr = GENERIC_WRITE;
|
|
||||||
|
|
||||||
} break;
|
|
||||||
}
|
|
||||||
if(flags.exclusive) {
|
|
||||||
disp = CREATE_NEW;
|
|
||||||
}
|
|
||||||
|
|
||||||
HANDLE fileHandle = CreateFileA(
|
|
||||||
name,
|
|
||||||
desaddr,
|
|
||||||
share,
|
|
||||||
NULL,
|
|
||||||
disp,
|
|
||||||
FILE_ATTRIBUTE_NORMAL,
|
|
||||||
NULL
|
|
||||||
);
|
|
||||||
FILE *file = (FILE *)fileHandle;
|
|
||||||
if(fileHandle == INVALID_HANDLE_VALUE) {
|
|
||||||
file = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return file;
|
|
||||||
}
|
|
||||||
|
|
||||||
int _os_fclose(FILE *file) {
|
|
||||||
HANDLE fileHandle = (HANDLE)file;
|
|
||||||
BOOL ok = CloseHandle(fileHandle);
|
|
||||||
return ok != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void _os_file_write(void* ctx, size_t n, const char str[]) {
|
|
||||||
DWORD written = 0;
|
|
||||||
WriteFile((HANDLE) ctx, str, n, &written, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _os_file_write_char(void* ctx, char ch) {
|
|
||||||
DWORD written = 0;
|
|
||||||
WriteFile((HANDLE) ctx, &ch, 1, &written, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
int system(const char* string) {
|
|
||||||
int wchars_required = MultiByteToWideChar(65001 /* UTF8 */, 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 /* UTF8 */, 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 = {};
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
|
@ -1,10 +1,7 @@
|
||||||
|
|
||||||
#include <_os.h>
|
#include <win.h>
|
||||||
|
|
||||||
#define WIN32_LEAN_AND_MEAN
|
|
||||||
#include<Windows.h>
|
|
||||||
#include<DbgHelp.h>
|
|
||||||
|
|
||||||
|
#include <signal.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
@ -54,32 +51,45 @@ static LONG _win32_handler(EXCEPTION_POINTERS *ExceptionInfo) {
|
||||||
return EXCEPTION_CONTINUE_SEARCH;
|
return EXCEPTION_CONTINUE_SEARCH;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _os_print_stack_trace() {
|
|
||||||
HANDLE process = GetCurrentProcess();
|
|
||||||
SymInitialize(process, NULL, TRUE);
|
|
||||||
|
|
||||||
void *stack[128];
|
void _setup_eh() {
|
||||||
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",
|
|
||||||
(int)(frames-i-1),
|
|
||||||
symbol->Address,
|
|
||||||
symbol->Name
|
|
||||||
);
|
|
||||||
}
|
|
||||||
free(symbol);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _os_init_eh() {
|
|
||||||
void *res = AddVectoredExceptionHandler(1, &_win32_handler);
|
void *res = AddVectoredExceptionHandler(1, &_win32_handler);
|
||||||
if(res == NULL) {
|
if(res == NULL) {
|
||||||
ExitProcess(-69420);
|
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;
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
|
||||||
|
#include <win.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
void _os_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",
|
||||||
|
// (int)(frames-i-1),
|
||||||
|
// symbol->Address,
|
||||||
|
// symbol->Name
|
||||||
|
// );
|
||||||
|
}
|
||||||
|
free(symbol);
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
|
||||||
|
#include <win.h>
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
// It's just mapped directly to HANDLE
|
||||||
|
struct FILE {
|
||||||
|
int unused;
|
||||||
|
};
|
||||||
|
|
||||||
|
FILE *stdout;
|
||||||
|
FILE *stdin;
|
||||||
|
FILE *stderr;
|
||||||
|
|
||||||
|
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 = {};
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
|
@ -5,8 +5,8 @@
|
||||||
// Based on these posts:
|
// Based on these posts:
|
||||||
// https://preshing.com/20120305/implementing-a-recursive-mutex/
|
// https://preshing.com/20120305/implementing-a-recursive-mutex/
|
||||||
// https://preshing.com/20120226/roll-your-own-lightweight-mutex/
|
// https://preshing.com/20120226/roll-your-own-lightweight-mutex/
|
||||||
#include "win.h"
|
#include <win.h>
|
||||||
#include "threads.h"
|
#include <threads.h>
|
||||||
|
|
||||||
void mtx_destroy(mtx_t *mtx) {
|
void mtx_destroy(mtx_t *mtx) {
|
||||||
CloseHandle(mtx->semaphore);
|
CloseHandle(mtx->semaphore);
|
|
@ -1,11 +1,20 @@
|
||||||
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "win.h"
|
#include <win.h>
|
||||||
|
|
||||||
// Store the time since we started running the process
|
// Store the time since we started running the process
|
||||||
static uint64_t timer_freq;
|
static uint64_t timer_freq;
|
||||||
static uint64_t timer_start;
|
static uint64_t timer_start;
|
||||||
|
|
||||||
|
void _setup_timer(void) {
|
||||||
|
LARGE_INTEGER freq, start;
|
||||||
|
QueryPerformanceFrequency(&freq);
|
||||||
|
QueryPerformanceCounter(&start);
|
||||||
|
timer_start = start.QuadPart;
|
||||||
|
timer_freq = freq.QuadPart;
|
||||||
|
}
|
||||||
|
|
||||||
int timespec_get(struct timespec *ts, int base) {
|
int timespec_get(struct timespec *ts, int base) {
|
||||||
if (base != TIME_UTC) return 0;
|
if (base != TIME_UTC) return 0;
|
||||||
|
|
||||||
|
@ -42,14 +51,3 @@ clock_t clock(void) {
|
||||||
|
|
||||||
return scaled_millis;
|
return scaled_millis;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _os_timing_init(void) {
|
|
||||||
LARGE_INTEGER freq, start;
|
|
||||||
if (QueryPerformanceFrequency(&freq) && QueryPerformanceCounter(&start)) {
|
|
||||||
timer_start = start.QuadPart;
|
|
||||||
timer_freq = freq.QuadPart;
|
|
||||||
} else {
|
|
||||||
// failure...
|
|
||||||
timer_start = timer_freq = UINT64_MAX;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
for(int i = 0; i != argc; ++i) {
|
||||||
|
char *arg = argv[i];
|
||||||
|
arg = arg;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in New Issue