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
|
||||
for /R src\%PLATFORM% %%F in (*.c) do (
|
||||
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 (
|
||||
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
|
||||
|
||||
#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 asdouble(x) ((union {double f; uint64_t i;}){x}).f
|
||||
|
||||
#include <_compiler.h>
|
||||
#if defined(_compiler_clang) || defined(_compiler_gcc)
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
#define just_do_it(t) __attribute__((unused)) volatile t
|
||||
#else
|
||||
#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
|
||||
|
||||
#include <_os.h>
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
#include <processenv.h>
|
||||
#include <shellapi.h>
|
||||
#include <DbgHelp.h>
|
||||
|
||||
struct _os_heap {
|
||||
HANDLE handle;
|
||||
};
|
||||
|
||||
void _os_timing_init(void);
|
||||
void _setup_timer(void);
|
||||
void _setup_eh();
|
||||
void _setup_heap();
|
||||
|
|
|
@ -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 <limits.h>
|
||||
#include <win.h>
|
||||
#include <stdbool.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "win.h"
|
||||
|
||||
// TODO: lock the heap before allocation (?)
|
||||
|
||||
HANDLE _heap;
|
||||
static HANDLE heap_handle;
|
||||
|
||||
static bool is_power_of_two(size_t s) {
|
||||
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);
|
||||
}
|
||||
|
||||
void _heap_setup(_os_heap *heap) {
|
||||
_heap = heap->handle;
|
||||
void _setup_heap() {
|
||||
heap_handle = GetProcessHeap();
|
||||
if (heap_handle == NULL) {
|
||||
ExitProcess(-42069);
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
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 aligned_block_start_i = align_forward(block_start_i, alignment);
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -61,7 +60,7 @@ void free(void *ptr) {
|
|||
if(ptr == NULL) {
|
||||
return;
|
||||
}
|
||||
HeapFree(_heap, 0, ptr);
|
||||
HeapFree(heap_handle, 0, ptr);
|
||||
}
|
||||
|
||||
void *malloc(size_t size) {
|
||||
|
@ -72,11 +71,12 @@ void *realloc(void *ptr, size_t size) {
|
|||
if (ptr == NULL) {
|
||||
if (size == 0) return NULL;
|
||||
|
||||
return HeapAlloc(_heap, 0, size);
|
||||
return HeapAlloc(heap_handle, 0, size);
|
||||
} else if (size == 0) {
|
||||
HeapFree(_heap, 0, ptr);
|
||||
HeapFree(heap_handle, 0, ptr);
|
||||
return NULL;
|
||||
} 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>
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include<Windows.h>
|
||||
#include<DbgHelp.h>
|
||||
#include <win.h>
|
||||
|
||||
#include <signal.h>
|
||||
#include <signal.h>
|
||||
#include <stddef.h>
|
||||
#include <inttypes.h>
|
||||
|
@ -54,32 +51,45 @@ static LONG _win32_handler(EXCEPTION_POINTERS *ExceptionInfo) {
|
|||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void _os_init_eh() {
|
||||
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;
|
||||
}
|
|
@ -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:
|
||||
// https://preshing.com/20120305/implementing-a-recursive-mutex/
|
||||
// https://preshing.com/20120226/roll-your-own-lightweight-mutex/
|
||||
#include "win.h"
|
||||
#include "threads.h"
|
||||
#include <win.h>
|
||||
#include <threads.h>
|
||||
|
||||
void mtx_destroy(mtx_t *mtx) {
|
||||
CloseHandle(mtx->semaphore);
|
|
@ -1,11 +1,20 @@
|
|||
|
||||
#include <time.h>
|
||||
#include <stdint.h>
|
||||
#include "win.h"
|
||||
#include <win.h>
|
||||
|
||||
// Store the time since we started running the process
|
||||
static uint64_t timer_freq;
|
||||
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) {
|
||||
if (base != TIME_UTC) return 0;
|
||||
|
||||
|
@ -42,14 +51,3 @@ clock_t clock(void) {
|
|||
|
||||
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