Temporary files + Some work on threads.h header

This commit is contained in:
bumbread 2023-02-15 18:37:23 +11:00
parent d5650150b1
commit 3fe99b72cb
18 changed files with 416 additions and 1797 deletions

View File

@ -3,56 +3,37 @@
#include <stdarg.h>
#if !defined(NULL)
#define NULL ((void *)0)
#endif
// 7.23.3 p.2: Header version
#define __STDC_VERSION_STDIO_H__ 202311L
// 7.23.3 p.3: Types
#if defined(_WIN32)
typedef unsigned long long size_t;
#else
typedef unsigned long size_t;
#endif
#if !defined(_mbstate_t_defined)
#define _mbstate_t_defined
typedef struct mbstate_t mbstate_t;
struct mbstate_t {
union {
unsigned short leftover;
unsigned short high_surrogate;
};
};
#endif
typedef struct FILE FILE;
typedef struct {
unsigned long long offset;
mbstate_t mbstate;
union {
unsigned short leftover;
unsigned short high_surrogate;
} mbstate;
} fpos_t;
// 7.23.3 p.4: Macros
#if !defined(NULL)
#define NULL ((void *)0)
#endif
#if !defined(__STDC_LIB_EXT1__)
#define __STDC_LIB_EXT1__
typedef int errno_t;
typedef size_t rsize_t;
#endif
#ifdef __STDC_WANT_SECURE_LIB__
#if !defined(__STDC_WANT_LIB_EXT1__)
#define __STDC_WANT_LIB_EXT1__ 1
#endif
#endif
#define _IONBF 0
#define _IOFBF 1
#define _IOLBF 2
#define BUFSIZ 512
#define EOF (-1)
#define FOPEN_MAX 1024
#define FOPEN_MAX 32
#ifdef _os_win
#define FILENAME_MAX 260
@ -60,6 +41,8 @@ typedef struct {
#define FILENAME_MAX 4096
#endif
#define _PRINTF_NAN_LEN_MAX 20
#define L_tmpnam FILENAME_MAX
#define SEEK_SET 0
@ -72,17 +55,21 @@ typedef struct {
#define TMP_MAX INT_MAX
#endif
extern FILE *stdout;
extern FILE *stderr;
extern FILE *stdin;
#define stdout _internal_stdout
#define stderr _internal_stderr
#define stdin _internal_stdin
extern FILE *_internal_stdout;
extern FILE *_internal_stderr;
extern FILE *_internal_stdin;
// File manipulation
int remove(const char *filename);
int rename(const char *oldname, const char *newname);
FILE *tmpfile(void);
char *tmpnam(char *s);
// Opening and closing files
char *tmpnam(char *s);
FILE *tmpfile(void);
FILE *fopen (const char *restrict filename, const char *restrict mode);
FILE *freopen(const char *restrict filename, const char *restrict mode, FILE *restrict stream);
int fclose (FILE *stream);

View File

@ -1,47 +1,59 @@
#pragma once
#define thread_local _Thread_local
// 7.28.1 p.3: Macros
#define ONCE_FLAG_INIT 1
#define TSS_DTOR_ITERATIONS 32
// TODO(bumbread): check the spec for whether thread_local needs to be declared
// in threads.h
#define thread_local _Thread_local
// 7.28.1 p.4: Types
#if !defined(_timespec_defined)
#define _timespec_defined
typedef unsigned long long time_t;
struct timespec {
time_t tv_sec;
long tv_nsec;
};
#define _timespec_defined
typedef unsigned long long time_t;
struct timespec {
time_t tv_sec;
long tv_nsec;
};
#endif
// TODO(bumbread): move this out to platform-specific folder
#if defined(_WIN32)
typedef struct cnd_t {
int idk_yet;
} cnd_t;
typedef struct cnd_t {
int idk_yet;
} cnd_t;
typedef struct thrd_t {
void* handle;
} thrd_t;
typedef struct thrd_t {
void* handle;
} thrd_t;
typedef struct tss_t {
int idk_yet;
} tss_t;
typedef struct tss_t {
int idk_yet;
} tss_t;
typedef struct mtx_t {
int type;
// Done to handle recursive mutexes
unsigned long recursion;
unsigned long owner;
_Atomic(int) counter;
void* semaphore;
} mtx_t;
typedef struct mtx_t {
int type;
// Done to handle recursive mutexes
unsigned long recursion;
unsigned long owner;
_Atomic(int) counter;
void* semaphore;
} mtx_t;
#else
#error "Not implemented"
#error "Not implemented"
#endif
typedef void(*tss_dtor_t) (void*);
typedef int (*thrd_start_t)(void*);
typedef int once_flag; // TODO: change this maybe?
// TODO(bumbread): this probably should be a mutex or a semaphore
// also probably can be implemented with interlocked increment
typedef int once_flag;
// 7.28.1 p.5: Enumeration constants
enum {
mtx_plain = 0,
@ -57,29 +69,7 @@ enum {
thrd_nomem
};
void call_once(once_flag *flag, void (*func)(void));
int cnd_init (cnd_t *cond);
int cnd_broadcast(cnd_t *cond);
void cnd_destroy (cnd_t *cond);
int cnd_signal (cnd_t *cond);
int cnd_wait (cnd_t *cond, mtx_t *mtx);
int cnd_timedwait(
cnd_t *restrict cond,
mtx_t *restrict mtx,
const struct timespec *restrict ts
);
void mtx_destroy (mtx_t *mtx);
int mtx_init (mtx_t *mtx, int type);
int mtx_unlock (mtx_t *mtx);
int mtx_trylock (mtx_t *mtx);
int mtx_lock (mtx_t *mtx);
int mtx_timedlock(
mtx_t *restrict mtx,
const struct timespec *restrict ts
);
// Thread functions
thrd_t thrd_current(void);
int thrd_create (thrd_t *thr, thrd_start_t func, void *arg);
int thrd_detach (thrd_t thr);
@ -92,7 +82,34 @@ int thrd_sleep(
);
_Noreturn void thrd_exit(int res);
// Mutex functions
void mtx_destroy (mtx_t *mtx);
int mtx_init (mtx_t *mtx, int type);
int mtx_unlock (mtx_t *mtx);
int mtx_trylock (mtx_t *mtx);
int mtx_lock (mtx_t *mtx);
int mtx_timedlock(
mtx_t *restrict mtx,
const struct timespec *restrict ts
);
// Thread-local storage functions
int tss_create(tss_t *key, tss_dtor_t dtor);
void tss_delete(tss_t key);
void *tss_get (tss_t key);
int tss_set (tss_t key, void *val);
// Condition functions
int cnd_init (cnd_t *cond);
int cnd_broadcast(cnd_t *cond);
void cnd_destroy (cnd_t *cond);
int cnd_signal (cnd_t *cond);
int cnd_wait (cnd_t *cond, mtx_t *mtx);
int cnd_timedwait(
cnd_t *restrict cond,
mtx_t *restrict mtx,
const struct timespec *restrict ts
);
// Call once
void call_once(once_flag *flag, void (*func)(void));

View File

@ -50,7 +50,6 @@
#include "conv/strpfx.c"
#include "conv/int.c"
#include "conv/float.c"
#include "fmt/fmt.c"
#include "stdlib/algorithm.c"
#include "stdlib/multibyte.c"
#include "stdlib/random.c"
@ -69,11 +68,11 @@
#include "os_win/cookie.c"
#include "os_win/assert.c"
#include "os_win/cmdline.c"
#include "os_win/entry.c"
#include "os_win/environment.c"
#include "os_win/heap.c"
#include "os_win/signal.c"
#include "os_win/stdio.c"
#include "os_win/threads.c"
#include "os_win/file.c"
#include "os_win/thread.c"
#include "os_win/time.c"
#include "os_win/entry.c"
#endif

View File

@ -1,164 +0,0 @@
#define FLAG_ZERO 0x0001 // "0"
#define FLAG_LEFT 0x0002 // "-"
#define FLAG_PLUS 0x0004 // "+"
#define FLAG_SPACE 0x0008 // " "
#define FLAG_HASH 0x0010 // "#"
#define FLAG_PREC 0x0020 // ".precision"
#define FLAG_LONG 0x0040 // "l"
#define FLAG_LLONG 0x0080 // "ll"
#define FLAG_SHORT 0x0100 // "h"
#define FLAG_CHAR 0x0200 // "hh"
#define FLAG_UPPER 0x0400 // for hex digits 0xa-0xf
struct fmt_t typedef fmt_t;
struct fmt_t {
int prec;
int width;
int flags;
};
#define ctype char
#define pfx(f) f
#include "fmt_string.h"
#include "fmt_stream.h"
#include "ints.h"
#include "fmt.h"
#undef ctype
#undef pfx
#define ctype wchar_t
#define pfx(f) w ## f
#include "fmt_string.h"
#include "fmt_stream.h"
#include "ints.h"
#include "fmt.h"
#undef ctype
#undef pfx
// fprintf family
static inline int fstream_outc(void *ctx, char c) {
FILE *file = ctx;
int result = fputc(c, file);
if(result == EOF) {
return -1;
}
return 1;
}
static inline int fstream_outw(void *ctx, wchar c) {
FILE *file = ctx;
int result = fputc((char)c, file); // TODO: utf8
if(result == EOF) {
return -1;
}
return 1;
}
static inline fmt_stream_t fstream_new(FILE *file) {
fmt_stream_t stream;
stream.w = 0;
stream.ctx = file;
stream.out_ctype = fstream_outc;
stream.out_wchar = fstream_outw;
stream.out_char = fstream_outc;
return stream;
}
int vfprintf(FILE *restrict file, const char *restrict string, va_list va) {
fmt_stream_t stream = fstream_new(file);
return fmt(&stream, string, va);
}
int vprintf(const char *restrict string, va_list va) {
return vfprintf(stdout, string, va);
}
int fprintf(FILE *restrict file, const char *restrict string, ...) {
va_list va;
va_start(va, string);
int result = vfprintf(file, string, va);
va_end(va);
return result;
}
int printf(const char *restrict string, ...) {
va_list va;
va_start(va, string);
int result = vfprintf(stdout, string, va);
va_end(va);
return result;
}
// s(n)printf family
struct str_slice_t typedef str_slice_t;
struct str_slice_t {
char *str;
size_t max_size;
size_t written;
};
static inline int sstream_outc(void *ctx, char c) {
str_slice_t *slice = ctx;
if(slice->written+1 < slice->max_size) {
return -1;
}
slice->str[slice->written++] = c;
return 1;
}
static inline int sstream_outw(void *ctx, wchar c) {
str_slice_t *slice = ctx;
// TODO: utf8
if(slice->written+1 < slice->max_size) {
return -1;
}
slice->str[slice->written++] = c;
return 1;
}
static inline fmt_stream_t sstream_new(str_slice_t *slice) {
fmt_stream_t stream;
stream.w = 0;
stream.ctx = slice;
stream.out_ctype = sstream_outc;
stream.out_wchar = sstream_outw;
stream.out_char = sstream_outc;
return stream;
}
int vsnprintf(char *restrict buf, size_t cbbuf, const char *restrict str, va_list va) {
str_slice_t slice;
slice.str = buf;
slice.max_size = cbbuf;
slice.written = 0;
fmt_stream_t stream = sstream_new(&slice);
return fmt(&stream, str, va);
}
int vsprintf(char *restrict buf, const char *restrict str, va_list va) {
str_slice_t slice;
slice.str = buf;
slice.max_size = SIZE_MAX;
slice.written = 0;
fmt_stream_t stream = sstream_new(&slice);
return fmt(&stream, str, va);
}
int snprintf(char *restrict buf, size_t cbbuf, const char *restrict str, ...) {
va_list va;
va_start(va, str);
int result = vsnprintf(buf, cbbuf, str, va);
va_end(va);
return result;
}
int sprintf(char *restrict buf, const char *restrict str, ...) {
va_list va;
va_start(va, str);
int result = vsprintf(buf, str, va);
va_end(va);
return result;
}

View File

@ -1,44 +0,0 @@
static inline int pfx(fmt_arg)(fmt_stream_t *stream, ctype const **strp, va_list va) {
ctype const *str = *strp;
fmt_t fmt = {0};
if(!pfx(fmt_read)(str, &fmt, va)) {
return 0;
}
switch(*str) {
case 'i':
case 'u':
case 'b':
case 'o':
case 'd':
case 'x':
case 'X':
{
int base;
int sign;
u64 abs = pfx(fmt_int_arg)(stream, &fmt, &str, &sign, &base, va);
if(pfx(fmt_int)(stream, fmt, sign, abs, base) == -1) {
return -1;
}
} break;
}
*strp = str;
return 1;
}
static inline int pfx(fmt)(fmt_stream_t *stream, ctype const *str, va_list va) {
stream->w = 0;
while(*str) {
if(*str == '%') {
++str;
int ok = pfx(fmt_arg)(stream, &str, va);
if(!ok) {
return -1;
}
}
else {
stream_out(stream, *str++);
}
}
return stream->w;
}

View File

@ -1,13 +0,0 @@
struct pfx(fmt_stream_t) typedef pfx(fmt_stream_t);
struct pfx(fmt_stream_t) {
int w;
void *ctx;
int (*pfx(out_ctype))(void *ctx, ctype ch);
int (*pfx(out_wchar))(void *ctx, wchar ch);
int (*pfx(out_char)) (void *ctx, char ch);
};
#define stream_out(s, ch) if((s->w++, !s->out_ctype(s->ctx, ch))) return -1
#define stream_outc(s, ch) if((s->w++, !s->out_char (s->ctx, ch))) return -1
#define stream_outw(s, ch) if((s->w++, !s->out_wchar(s->ctx, ch))) return -1

View File

@ -1,74 +0,0 @@
static inline int pfx(fmt_isdigit)(ctype ch) {
return '0' <= ch && ch <= '9';
}
static inline int pfx(fmt_atoi)(ctype const **sp, int *err) {
int i = 0;
ctype const *s = *sp;
while(pfx(fmt_isdigit(*s))) {
int d = *s-'0';
if(i > (INT_MAX - d)/10) {
*err = 1;
return 0;
}
i = 10*i + d;
++s;
}
*sp = s;
return i;
}
static inline int pfx(fmt_read)(const ctype *str, fmt_t *fmt, va_list va) {
int flags = 0;
// Parse flag field
{
int isflag = 0;
do {
isflag = 1;
switch(*str) {
case '0': flags |= FLAG_ZERO; break;
case '-': flags |= FLAG_LEFT; break;
case '+': flags |= FLAG_PLUS; break;
case ' ': flags |= FLAG_SPACE; break;
case '#': flags |= FLAG_HASH; break;
default: isflag = 0;
}
if(isflag) ++str;
} while(isflag);
// If '-' and '0' are together we just discard '0'
if(flags & FLAG_LEFT) flags &= ~FLAG_ZERO;
}
// Parse width field
int width = 0;
if(pfx(fmt_isdigit(*str))) {
int err = 0;
width = pfx(fmt_atoi(&str, &err));
if(err) return 0;
}
else if(*str == '*') {
++str;
width = va_arg(va, int);
if(width < 0) {
width = -width;
flags |= FLAG_LEFT;
}
}
// If present, parse the precision field
int prec = 0;
if(*str == '.') {
flags |= FLAG_PREC;
++str;
if(pfx(fmt_isdigit(*str))) {
int err = 0;
prec = pfx(fmt_atoi(&str, &err));
if(err) return -1;
}
else if(*str == '*') {
++str;
prec = va_arg(va, int);
prec = (prec > 0? prec : 0);
}
}
return 1;
}

View File

@ -1,95 +0,0 @@
#define ctype char
#define pfx(f) f
#include "gen_fmt.h"
#undef ctype
#undef pfx
#define ctype wchar_t
#define pfx(f) w ## f
#include "gen_fmt.h"
#undef ctype
#undef pfx
static int fprintfcb(void *ctx, char ch) {
FILE *f = ctx;
return fputc(ch, f) != EOF;
}
struct str_ctx_t typedef str_ctx_t;
struct str_ctx_t {
char *str;
size_t n;
size_t i;
};
static int sprintfcb(void *ctx, char ch) {
str_ctx_t *stream = ctx;
stream->str[stream->i++] = ch;
return 1;
}
static int snprintfcb(void *ctx, char ch) {
str_ctx_t *stream = ctx;
if(stream->i >= stream->n) {
return 0;
}
stream->str[stream->i++] = ch;
return 1;
}
int vfprintf(FILE *stream, const char *fmt, va_list args) {
return vprintfcb(stream, fprintfcb, fmt, args);
}
int vprintf(const char *fmt, va_list args) {
return vprintfcb(stdout, fprintfcb, fmt, args);
}
int fprintf(FILE *stream, const char *fmt, ...) {
va_list args;
va_start(args, fmt);
int len = vfprintf(stream, fmt, args);
va_end(args);
return len;
}
int printf(const char *fmt, ...) {
va_list args;
va_start(args, fmt);
int len = vprintf(fmt, args);
va_end(args);
return len;
}
int vsprintf(char *buf, char const *fmt, va_list args) {
str_ctx_t ctx = {0};
ctx.str = buf;
return vprintfcb(&ctx, sprintfcb, fmt, args);
}
int vsnprintf(char *buf, size_t sz, char const *fmt, va_list args) {
str_ctx_t ctx = {0};
ctx.str = buf;
ctx.n = sz;
return vprintfcb(&ctx, snprintfcb, fmt, args);
}
int sprintf(char *buf, char const *fmt, ...) {
va_list args;
va_start(args, fmt);
int len = vsprintf(buf, fmt, args);
va_end(args);
return len;
}
int snprintf(char *buf, size_t sz, char const *fmt, ...) {
va_list args;
va_start(args, fmt);
int len = vsnprintf(buf, sz, fmt, args);
va_end(args);
return len;
}

View File

@ -1,883 +0,0 @@
typedef int (pfx(cbfn))(void *ctx, ctype ch);
#define FLAG_ZERO 0x0001 // "0"
#define FLAG_LEFT 0x0002 // "-"
#define FLAG_PLUS 0x0004 // "+"
#define FLAG_SPACE 0x0008 // " "
#define FLAG_HASH 0x0010 // "#"
#define FLAG_PREC 0x0020 // ".precision"
#define FLAG_LONG 0x0040 // "l"
#define FLAG_LLONG 0x0080 // "ll"
#define FLAG_SHORT 0x0100 // "h"
#define FLAG_CHAR 0x0200 // "hh"
#define FLAG_UPPER 0x0400 // for hex digits 0xa-0xf
// Helper function declaration
static inline int pfx(_isdigit)(ctype ch);
static inline int pfx(_atoi)(ctype const **sp, int *err);
static inline int pfx(_ntoa)(
int w,
void *ctx,
pfx(cbfn) cb,
int neg,
unsigned long long value,
int base,
int prec,
int width,
int flags
);
static inline int pfx(_dtoh)(
int w,
void *ctx,
pfx(cbfn) cb,
double value,
int prec,
int width,
int flags
);
static inline int pfx(_dtoa)(
int w,
void *ctx,
pfx(cbfn) cb,
decfloat_t value,
int prec,
int width,
int flags
);
static inline int pfx(_etoa)(
int w,
void *ctx,
pfx(cbfn) cb,
decfloat_t value,
int prec,
int width,
int flags
);
static inline int pfx(_infnantoa)(
int w,
void *ctx,
pfx(cbfn) cb,
double value,
int prec,
int width,
int flags
);
#define out(ch) do { if((w++, !cb(ctx, (ch)))) return -1; } while(0)
#define print_lwidth_spaces(flags, pad) \
do if(!(flags & FLAG_LEFT) && !(flags & FLAG_ZERO)) while(pad-- > 0) { \
out(' '); \
} \
while(0)
#define print_lwidth_zeros(flags, pad) \
do if(!(flags & FLAG_LEFT) && (flags & FLAG_ZERO)) while(pad-- > 0) { \
out('0'); \
} \
while(0)
#define print_rwidth(flags, pad) \
if(flags & FLAG_LEFT) while(pad-- > 0) { \
out(' '); \
}
// Generic print
static int pfx(vprintfcb)(
void *ctx,
pfx(cbfn) *cb,
const ctype *fmt,
va_list va
) {
int w = 0;
while(*fmt) {
// Write a character if it's not a '%' sign
while(*fmt && *fmt != '%') {
out(*fmt++);
continue;
}
if(*fmt == '%') {
++fmt;
}
// Parse flags
int flags = 0;
int isflag = 0;
do {
isflag = 1;
switch(*fmt) {
case '0': flags |= FLAG_ZERO; break;
case '-': flags |= FLAG_LEFT; break;
case '+': flags |= FLAG_PLUS; break;
case ' ': flags |= FLAG_SPACE; break;
case '#': flags |= FLAG_HASH; break;
default: isflag = 0;
}
if(isflag) ++fmt;
} while(isflag);
if(flags & FLAG_LEFT) flags &= ~FLAG_ZERO;
// Parse width field
int width = 0;
if(pfx(_isdigit(*fmt))) {
int err = 0;
width = pfx(_atoi(&fmt, &err));
if(err) return -1;
}
else if(*fmt == '*') {
++fmt;
width = va_arg(va, int);
if(width < 0) {
width = -width;
flags |= FLAG_LEFT;
}
}
// If present, parse the precision field
int prec = 0;
if(*fmt == '.') {
flags |= FLAG_PREC;
++fmt;
if(pfx(_isdigit(*fmt))) {
int err = 0;
prec = pfx(_atoi(&fmt, &err));
if(err) return -1;
}
else if(*fmt == '*') {
++fmt;
prec = va_arg(va, int);
prec = (prec > 0? prec : 0);
}
}
// Parse length field
switch(*fmt) {
case 'l':
++fmt;
flags |= FLAG_LONG;
if(*fmt == 'l') {
++fmt;
flags |= FLAG_LLONG;
}
break;
case 'h':
++fmt;
flags |= FLAG_SHORT;
if(*fmt == 'h') {
++fmt;
flags |= FLAG_CHAR;
}
break;
case 'j':
++fmt;
if(sizeof(intmax_t) == sizeof(long))
flags |= FLAG_LONG;
else flags |= FLAG_LLONG;
break;
case 'z':
++fmt;
if(sizeof(size_t) == sizeof(long))
flags |= FLAG_LONG;
else flags |= FLAG_LLONG;
break;
case 't':
++fmt;
if(sizeof(ptrdiff_t) == sizeof(long))
flags |= FLAG_LONG;
else flags |= FLAG_LLONG;
break;
case 'L':
++fmt;
break;
default:
break;
}
// Print according to specifier
switch(*fmt) {
case 'd':
case 'i':
case 'u':
case 'x':
case 'X':
case 'o':
case 'b': {
// Figure out the signedness and base
int base = 10;
if(*fmt == 'x' || *fmt == 'X') base = 16;
if(*fmt == 'o') base = 8;
if(*fmt == 'b') base = 2;
int signd = (*fmt == 'i' || *fmt == 'd');
// Figure out flags
if(*fmt == 'X') flags |= FLAG_UPPER;
if(base == 10) flags &= ~FLAG_HASH;
if(!signd) flags &= ~(FLAG_PLUS|FLAG_SPACE);
if(flags & FLAG_PREC) flags &= ~FLAG_ZERO;
++fmt;
// Read-in the integer argument from var args
int neg = 0;
unsigned long long value = 0;
if(signd) {
long long num;
if(flags & FLAG_LLONG)
num = (long long)va_arg(va, long long);
else if(flags & FLAG_LONG)
num = (long long)va_arg(va, long);
else
num = (long long)va_arg(va, int);
// Avoiding UB on unary negation like a bitch
if(num == LLONG_MIN) {
neg = 1;
value = (unsigned long long)LLONG_MAX + 1;
}
else {
neg = num >= 0? 0 : 1;
num = num >= 0? num : -num;
value = (unsigned long long)num;
}
}
else {
if(flags & FLAG_LLONG)
value = (unsigned long long)va_arg(va, unsigned long long);
else if(flags & FLAG_LONG)
value = (unsigned long long)va_arg(va, unsigned long);
else
value = (unsigned long long)va_arg(va, unsigned int);
}
// Output integer
w = pfx(_ntoa)(w, ctx, cb, neg, value, base, prec, width, flags);
if(w < 0) return -1;
} break;
case 'a':
case 'A': {
if(*fmt == 'A') flags |= FLAG_UPPER;
++fmt;
double value = va_arg(va, double);
w = pfx(_dtoh)(w, ctx, cb, value, prec, width, flags);
if(w < 0) return -1;
} break;
case 'e':
case 'E':
case 'f':
case 'F':
case 'g':
case 'G': {
if(*fmt == 'E' || *fmt == 'F' || *fmt == 'G') flags |= FLAG_UPPER;
char conv = tolower(*fmt);
++fmt;
double value = va_arg(va, double);
int class = fpclassify(value);
if(class == FP_INFINITE || class == FP_NAN) {
return pfx(_infnantoa)(w, ctx, cb, value, prec, width, flags);
}
decfloat_t dec_value = f64_to_decimal(value);
if(conv == 'f') {
w = pfx(_dtoa)(w, ctx, cb, dec_value, prec, width, flags);
}
else if(conv == 'e') {
w = pfx(_etoa)(w, ctx, cb, dec_value, prec, width, flags);
}
else {
int P = prec;
if(!(flags & FLAG_PREC)) P = 6;
if(prec == 0) P = 1;
int64_t E;
{
if(class == FP_ZERO) {
E = 0;
}
else {
E = dec_value.exponent;
}
}
if(class == FP_SUBNORMAL || class == FP_ZERO) {
E = 0;
}
flags |= FLAG_PREC;
if(P > E && E >= -4) {
w = pfx(_dtoa)(w, ctx, cb, dec_value, P-(E+1), width, flags);
}
else {
w = pfx(_etoa)(w, ctx, cb, dec_value, P-1, width, flags);
}
}
if(w < 0) return -1;
}break;
case 'c': {
++fmt;
int ch = va_arg(va, int);
int pad = width-1;
// Print width left-pad
if(!(flags & FLAG_LEFT) && !(flags & FLAG_ZERO)) while(pad-- > 0) {
out(' ');
}
out(ch);
// Print right-pad
if(flags & FLAG_LEFT) while(pad-- > 0) {
out(' ');
}
} break;
case 's': {
++fmt;
char *str = NULL;
wchar_t *wstr = NULL;
int len = 0;
if(flags & FLAG_LONG) {
wstr = va_arg(va, wchar_t *);
wchar_t *s = wstr;
while(*s++!=0) ++len;
int pad = width - len;
// Print width left-pad
if(!(flags & FLAG_LEFT) && !(flags & FLAG_ZERO)) while(pad-- > 0) {
out(' ');
}
// Print string
mbstate_t ps = {0};
for(int i = 0; i < len; ++i) {
if(sizeof(ctype) == 2) {
out(wstr[i]);
}
else {
// char utf8[5];
// char *s = utf8;
// size_t r = c16rtomb(s, wstr[i], &ps);
// if(r == (size_t)(-1)) return -1;
// if(r != 0) {
// while(*s != 0) {
// out(*s++);
// }
// }
}
}
// Print right-pad
if(flags & FLAG_LEFT) while(pad-- > 0) {
out(' ');
}
}
else {
str = va_arg(va, char *);
char *s = str;
if(flags & FLAG_PREC) {
while(*s++!=0 && len<prec) ++len;
}
else {
while(*s++!=0) ++len;
}
int pad = width - len;
// Print width left-pad
if(!(flags & FLAG_LEFT) && !(flags & FLAG_ZERO)) while(pad-- > 0) {
out(' ');
}
// Print string
//mbstate_t ps = {0};
for(int i = 0; i < len; ++i) {
out(str[i]);
}
// Print right-pad
if(flags & FLAG_LEFT) while(pad-- > 0) {
out(' ');
}
}
} break;
case 'p': {
++fmt;
void *ptr = va_arg(va, void *);
unsigned long long iptr = (unsigned long long)(uintptr_t)ptr;
w = pfx(_ntoa)(w, ctx, cb, 0, iptr, 16, 16, 0, FLAG_HASH);
if(w < 0) return -1;
} break;
case 'n': {
++fmt;
int *p = va_arg(va, int *);
*p = w;
} break;
case '%': {
++fmt;
out('%');
} break;
}
}
return w;
}
static inline int pfx(_isdigit)(ctype ch) {
return '0' <= ch && ch <= '9';
}
static inline int pfx(_atoi)(ctype const **sp, int *err) {
int i = 0;
ctype const *s = *sp;
while(pfx(_isdigit(*s))) {
int d = *s-'0';
if(i > (INT_MAX - d)/10) {
*err = 1;
return 0;
}
i = 10*i + d;
++s;
}
*sp = s;
return i;
}
static inline int pfx(_ntoa)(
int w,
void *ctx,
pfx(cbfn) cb,
int neg,
unsigned long long value,
int base,
int prec,
int width,
int flags
) {
// We'll Write digits into buf in reverse and then call _out_rbuf
int ndigits = 0;
static ctype digits[64];
// Remove hash flag for 0 values
if(value == 0) flags &= ~FLAG_HASH;
// Write digits to buffer in reverse (starting from least significant)
do {
int d = (int)(value%base);
value /= base;
if(d < 10)
d += '0';
else if(flags & FLAG_UPPER)
d += 'A' - 10;
else d += 'a' - 10;
digits[ndigits++] = d;
} while(value);
// Figure out the length of the prefix (part of number before digit stirng)
int pref_len = 0;
if(flags & FLAG_HASH) pref_len = base == 8? 1 : 2;
else if(neg) pref_len = 1;
else if(flags & FLAG_PLUS) pref_len = 1;
else if(flags & FLAG_SPACE) pref_len = 1;
if(ndigits > prec) prec = ndigits;
int num_len = pref_len + prec;
int pad_len = width - num_len;
if(!(flags & FLAG_LEFT)) {
ctype pad_ch = ' ';
if(flags & FLAG_ZERO) pad_ch = '0';
while(pad_len-- > 0) {
out(pad_ch);
}
}
// Print width left-pad if it's made out of space
if(!(flags & FLAG_LEFT) && !(flags & FLAG_ZERO)) while(pad_len-- > 0) {
out(' ');
}
// Print prefix
if(flags & FLAG_HASH) {
out('0');
if(base == 16) { out('x'); }
else if(base == 2) { out('b'); }
}
else if(neg) { out('-'); }
else if(flags & FLAG_PLUS) { out('+'); }
else if(flags & FLAG_SPACE) { out(' '); }
// Print width left-pad if it's made out of zero
if(!(flags & FLAG_LEFT) && (flags & FLAG_ZERO)) while(pad_len-- > 0) {
out('0');
}
// Print zero-pad due to precision
for(int i = ndigits; i < prec; ++i) {
out('0');
}
// Output buffer in reverse
if(ndigits) while(ndigits--) {
out(digits[ndigits]);
}
// Print right-pad
if(flags & FLAG_LEFT) while(pad_len-- > 0) {
out(' ');
}
return w;
}
static inline int pfx(_infnantoa)(
int w,
void *ctx,
pfx(cbfn) cb,
double value,
int prec,
int width,
int flags
) {
char const *name = NULL;
int nchars = 0;
if(isinf(value)) name = "inf", nchars = 3;
if(isnan(value)) name = "nan", nchars = 3;
// Figure out prefix
int pref_len = 0;
u64 bits = F64_BITS(value);
u64 mant = F64_MANT(bits);
int neg = F64_SIGN(bits) & (mant == 0);
if(neg) pref_len = 1;
else if(flags & FLAG_PLUS) pref_len = 1;
else if(flags & FLAG_SPACE) pref_len = 1;
// Figure out pad
int str_len = pref_len + nchars;
int pad_len = width - str_len;
// Print left-pad
if(!(flags & FLAG_LEFT)) {
while(pad_len-- > 0) {
out(' ');
}
}
// Print the prefix
if(neg) out('-');
else if(flags & FLAG_PLUS) out('+');
else if(flags & FLAG_SPACE) out(' ');
// Print the string
while(*name) {
out(*name++);
}
// Print right-pad
if(flags & FLAG_LEFT) {
while(pad_len-- > 0) {
out(' ');
}
}
return w;
}
static inline int pfx(_dtoh)(
int w,
void *ctx,
pfx(cbfn) cb,
double value,
int prec,
int width,
int flags
) {
// Filter out inifnities and NaN
{
int class = fpclassify(value);
if(class == FP_INFINITE || class == FP_NAN) {
return pfx(_infnantoa)(w, ctx, cb, value, prec, width, flags);
}
}
// Deconstruct the float
u64 bits = F64_BITS(value);
u64 flt_sgn = F64_SIGN(bits);
u64 flt_mnt = F64_MANT(bits);
i64 flt_exp = F64_BEXP(bits);
u64 frc;
u64 mnt;
i64 exp;
{
mnt = flt_mnt;
exp = flt_exp - 0x3ff;
if(flt_exp == 0 && flt_mnt == 0) {
exp = 0;
}
}
// Calculate widths of different number parts and extract some data
static ctype frc_buffer[64] = {0};
static ctype exp_buffer[64] = {0};
ctype *frc_buf = frc_buffer + sizeof frc_buffer;
ctype *exp_buf = exp_buffer + sizeof exp_buffer;
ctype sgn_ch;
ctype exp_sgn_ch;
int has_sgn;
int has_point;
int nfrc = 0;
int nexp = 0;
int nfrcp = 0;
{
// Sign
if(flt_sgn) {
has_sgn = 1;
sgn_ch = '-';
}
else if(flags & FLAG_PLUS) {
has_sgn = 1;
sgn_ch = '+';
}
else if(flags & FLAG_SPACE) {
has_sgn = 1;
sgn_ch = ' ';
}
// Fractional part
frc = mnt;
if(frc != 0) {
while(!(frc & 0xf)) {
frc >>= 4;
}
}
u64 f = frc;
do {
int d = f % 16;
f /= 16;
*--frc_buf = fromdigit(d, flags & FLAG_UPPER);
} while(f != 0);
// Frac/whole digits
if(flags & FLAG_PREC) {
nfrcp = prec;
}
else {
nfrcp = nfrc;
}
// Decimal point
has_point = 1;
if(nfrc == 0 && !(flags & FLAG_HASH)) {
has_point = 0;
}
// Exponent
i64 e = exp;
if(e < 0) {
exp_sgn_ch = '-';
e = -e;
}
else {
exp_sgn_ch = '+';
}
do {
*--exp_buf = (e%10) + '0';
e /= 10;
nexp ++;
} while(e != 0);
}
// Figure out the width of a float
int nfloat = has_sgn + 2 + 1 + has_point + nfrcp + 1 + 1 + nexp;
int pad = MIN(0, width - nfloat);
print_lwidth_spaces(flags, pad);
if(has_sgn) {
out(sgn_ch);
}
out('0');
out((flags & FLAG_UPPER)? 'X' : 'x');
print_lwidth_zeros(flags, pad);
out((flt_exp == 0) ? '0' : '1');
if(has_point) {
out('.');
}
int i;
for(i = 0; i != nfrcp; ++i) {
if(i < nfrc) {
out(frc_buf[i]);
}
else {
out('0');
}
}
out((flags & FLAG_UPPER)? 'P' : 'p');
out(exp_sgn_ch);
for(int i = 0; i != nexp; ++i) {
out(exp_buf[i]);
}
print_rwidth(flags, pad);
return w;
}
static inline int pfx(_dtoa)(
int w,
void *ctx,
pfx(cbfn) cb,
decfloat_t value,
int prec,
int width,
int flags
) {
int64_t exp = value.exponent;
int64_t mant = value.mantissa;
// Figure out how many digits does mantissa take up (mant_digits_n)
// and the number of digits after decimal point (prec)
// and the number of digits before decimal point (while_digits_n)
static ctype mant_buf[64] = {0};
int whole_digits_n;
int mant_digits_n = 0;
{
int64_t m = mant;
do {
mant_buf[mant_digits_n++] = m % 10 + '0';
m /= 10;
} while(m != 0);
}
if((flags & FLAG_PREC) == 0) {
prec = 6;
}
whole_digits_n = mant_digits_n + exp;
if(whole_digits_n <= 0) whole_digits_n = 1;
// Figure out how many symbols decimal point takes up (0 or 1)
int decimal_point_n = 1;
if(prec == 0) {
decimal_point_n = 0;
if(flags & FLAG_HASH) {
decimal_point_n = 1;
}
}
// Figure out sign symbol and number of chars it takes up (0 or 1)
int sign_n = 0;
ctype sign_ch;
if(value.sign) {
sign_n = 1;
sign_ch = '-';
}
else if(flags & FLAG_PLUS) {
sign_n = 1;
sign_ch = '+';
}
else if(flags & FLAG_SPACE) {
sign_n = 1;
sign_ch = ' ';
}
// Figure out the width of the number
int significand_width = whole_digits_n + decimal_point_n + prec;
int n_width = sign_n + significand_width;
// Figure out width-padding required
int pad = 0;
if(width > n_width) pad = width - n_width;
// Print width left-pad if it's made out of space
if(!(flags & FLAG_LEFT) && !(flags & FLAG_ZERO)) while(pad-- > 0) {
out(' ');
}
// Print sign if there
if(sign_n)
out(sign_ch);
// Print width left-pad if it's made out of zero
if(!(flags & FLAG_LEFT) && (flags & FLAG_ZERO)) while(pad-- > 0) {
out('0');
}
// Print whole part
while(whole_digits_n--) {
if(-exp >= mant_digits_n) {
out('0');
}
else {
out(mant_buf[--mant_digits_n]);
}
++exp;
}
// Print decimal point
if(decimal_point_n) out('.');
// Print fractional part that's made out of digits
int prec_digs = prec < mant_digits_n ? prec : mant_digits_n;
while(mant_digits_n < prec_digs) {
if(-exp >= mant_digits_n) {
out('0');
}
else {
out(mant_buf[--mant_digits_n]);
}
++exp;
}
while(prec_digs-- > 0) {
out('0');
}
// Print right-pad
if(flags & FLAG_LEFT) while(pad-- > 0) {
out(' ');
}
return w;
}
static inline int pfx(_etoa)(
int w,
void *ctx,
pfx(cbfn) cb,
decfloat_t value,
int prec,
int width,
int flags
) {
int64_t exp = value.exponent;
int64_t mant = value.mantissa;
// Figure out how many digits does mantissa take up (mant_digits_n)
// and the number of digits after decimal point (prec)
static ctype mant_buf[64] = {0};
int mant_digits_n = 0;
{
int64_t m = mant;
do {
mant_buf[mant_digits_n++] = m % 10 + '0';
m /= 10;
} while(m != 0);
}
mant_digits_n -= 1;
// Need to adjust exponent based on the amount of digits in the mantissa
exp += mant_digits_n;
if((flags & FLAG_PREC) == 0) {
prec = 6;
}
// Figure out how many symbols decimal point takes up (0 or 1)
int decimal_point_n = 1;
if(prec == 0) {
decimal_point_n = 0;
if(flags & FLAG_HASH) {
decimal_point_n = 1;
}
}
// Figure out how many digits exponent take up and it's sign
// also save exponent digits to a buffer starting from LSD
static ctype exp_buf[64] = {0};
int exp_digits_n = 0;
ctype exp_sign;
if(exp < 0) {
exp_sign = '-';
exp = -exp;
}
else {
exp_sign = '+';
}
{
int64_t e = exp;
do {
exp_buf[exp_digits_n++] = e % 10 + '0';
e /= 10;
} while(e != 0);
}
// Figure out sign symbol and number of chars it takes up (0 or 1)
int sign_n = 0;
ctype sign_ch;
if(value.sign) {
sign_n = 1;
sign_ch = '-';
}
else if(flags & FLAG_PLUS) {
sign_n = 1;
sign_ch = '+';
}
else if(flags & FLAG_SPACE) {
sign_n = 1;
sign_ch = ' ';
}
// Figure out the width of the number
int significand_width = 1 + decimal_point_n + prec;
int exp_part_width = 2 /*e+-*/ + exp_digits_n;
int n_width = sign_n + significand_width + exp_part_width;
// Figure out width-padding required
int pad = 0;
if(width > n_width) pad = width - n_width;
// Print width left-pad if it's made out of space
if(!(flags & FLAG_LEFT) && !(flags & FLAG_ZERO)) while(pad-- > 0) {
out(' ');
}
// Print sign if there
if(sign_n)
out(sign_ch);
// Print width left-pad if it's made out of zero
if(!(flags & FLAG_LEFT) && (flags & FLAG_ZERO)) while(pad-- > 0) {
out('0');
}
// Print whole part
out(mant_buf[mant_digits_n]);
// Print decimal point
if(decimal_point_n) out('.');
// Print precision padding
for(int i = mant_digits_n; i < prec; ++i) {
out('0');
}
if(prec < mant_digits_n) mant_digits_n = prec;
while(mant_digits_n--)
out(mant_buf[mant_digits_n]);
// Print the exponent part
out((flags & FLAG_UPPER)? 'E' : 'e');
out(exp_sign);
while(exp_digits_n--)
out(exp_buf[exp_digits_n]);
// Print right-pad
if(flags & FLAG_LEFT) while(pad-- > 0) {
out(' ');
}
return w;
}
#undef out

View File

@ -1,150 +0,0 @@
static inline u64 pfx(fmt_int_arg)(
fmt_stream_t *stream,
fmt_t *fmt,
ctype const **strp,
int *signp,
int *basep,
va_list va
) {
ctype const *str = *strp;
// Get integer properties
int base;
int is_signed;
switch(*str) {
case 'o': base = 8; break;
case 'b': base = 2; break;
case 'x':
case 'X': base = 16; break;
default: base = 10;
}
switch(*str) {
case 'd': is_signed = 1; break;
case 'i': is_signed = 1; break;
default: is_signed = 0;
}
if(*str == 'X') {
fmt->flags |= FLAG_UPPER;
}
// Discard some flags
if(base == 10) {
fmt->flags &= ~FLAG_HASH;
}
if(!is_signed) {
fmt->flags &= ~(FLAG_PLUS|FLAG_SPACE);
}
if(fmt->flags & FLAG_PREC) {
fmt->flags &= ~FLAG_ZERO;
}
// Parse sign and abs value of an integer
int sign = 0;
u64 abs_value = 0;
if(is_signed) {
i64 num;
if(fmt->flags & FLAG_LLONG) {
num = (i64)va_arg(va, intll);
}
else if(fmt->flags & FLAG_LONG) {
num = (i64)va_arg(va, intl);
}
else {
num = (i64)va_arg(va, int);
}
// Handle overflow on '-'
if(num == LLONG_MIN) {
sign = 1;
abs_value = (u64)LLONG_MAX + 1;
}
else {
sign = num >= 0? 0 : 1;
num = num >= 0? num : -num;
abs_value = (u64)num;
}
}
else {
if(fmt->flags & FLAG_LLONG) {
abs_value = (u64)va_arg(va, intull);
}
else if(fmt->flags & FLAG_LONG) {
abs_value = (u64)va_arg(va, intul);
}
else {
abs_value = (u64)va_arg(va, intu);
}
}
++str;
*strp = str;
*basep = base;
*signp = sign;
return abs_value;
}
static inline int pfx(fmt_int)(
fmt_stream_t *stream,
fmt_t fmt,
int neg,
u64 value,
int base) {
// We'll Write digits into buf in reverse and then call _out_rbuf
int ndigits = 0;
ctype digits[64] = {0};
// Remove hash flag for 0 values
if(value == 0) fmt.flags &= ~FLAG_HASH;
// Write digits to buffer in reverse (starting from least significant)
do {
int d = (int)(value%base);
value /= base;
if(d < 10)
d += '0';
else if(fmt.flags & FLAG_UPPER)
d += 'A' - 10;
else d += 'a' - 10;
digits[ndigits++] = d;
} while(value);
// Figure out the length of the prefix (part of number before digit stirng)
int pref_len = 0;
if(fmt.flags & FLAG_HASH) pref_len = base == 8? 1 : 2;
else if(neg) pref_len = 1;
else if(fmt.flags & FLAG_PLUS) pref_len = 1;
else if(fmt.flags & FLAG_SPACE) pref_len = 1;
if(ndigits > fmt.prec) fmt.prec = ndigits;
int num_len = pref_len + fmt.prec;
int pad_len = fmt.width - num_len;
if(!(fmt.flags & FLAG_LEFT)) {
ctype pad_ch = ' ';
if(fmt.flags & FLAG_ZERO) pad_ch = '0';
while(pad_len-- > 0) {
stream_out(stream, pad_ch);
}
}
// Print width left-pad if it's made out of space
if(!(fmt.flags & FLAG_LEFT) && !(fmt.flags & FLAG_ZERO)) while(pad_len-- > 0) {
stream_out(stream, ' ');
}
// Print prefix
if(fmt.flags & FLAG_HASH) {
stream_out(stream, '0');
if(base == 16) { stream_out(stream, 'x'); }
else if(base == 2) { stream_out(stream, 'b'); }
}
else if(neg) { stream_out(stream, '-'); }
else if(fmt.flags & FLAG_PLUS) { stream_out(stream, '+'); }
else if(fmt.flags & FLAG_SPACE) { stream_out(stream, ' '); }
// Print width left-pad if it's made out of zero
if(!(fmt.flags & FLAG_LEFT) && (fmt.flags & FLAG_ZERO)) while(pad_len-- > 0) {
stream_out(stream, '0');
}
// Print zero-pad due to precision
for(int i = ndigits; i < fmt.prec; ++i) {
stream_out(stream, '0');
}
// Output buffer in reverse
if(ndigits) while(ndigits--) {
stream_out(stream, digits[ndigits]);
}
// Print right-pad
if(fmt.flags & FLAG_LEFT) while(pad_len-- > 0) {
stream_out(stream, ' ');
}
return stream->w;
}

View File

@ -18,12 +18,12 @@ static void _print_stack_trace() {
SymFromAddr(process, (DWORD64)stack[i], 0, symbol);
// if(strcmp(symbol->Name, "BaseThreadInitThunk") == 0) break;
// if(strcmp(symbol->Name, "mainCRTStartup") == 0) break;
printf(//" %u: 0x%"PRIx64" (%s)\n",
" %d: %s\n",
(int)(frames-i-1),
//symbol->Address,
symbol->Name
);
// printf(//" %u: 0x%"PRIx64" (%s)\n",
// " %d: %s\n",
// (int)(frames-i-1),
// //symbol->Address,
// symbol->Name
// );
}
free(symbol);
}
@ -39,10 +39,10 @@ void _assert(
// For GUI application we display the info into a messagebox
char buf[1024];
int i = 0;
i += snprintf(buf+i, sizeof buf-i, "Assertion failed: %s\n", cond);
i += snprintf(buf+i, sizeof buf-i, " Function: %s\n", func);
i += snprintf(buf+i, sizeof buf-i, " File: %s\n", file);
i += snprintf(buf+i, sizeof buf-i, " Line: %d\n", line);
// i += snprintf(buf+i, sizeof buf-i, "Assertion failed: %s\n", cond);
// i += snprintf(buf+i, sizeof buf-i, " Function: %s\n", func);
// i += snprintf(buf+i, sizeof buf-i, " File: %s\n", file);
// i += snprintf(buf+i, sizeof buf-i, " Line: %d\n", line);
display_msg:
int reaction = MessageBoxA(NULL, buf, "Assertion Failed", 0x00000032L);
switch(reaction) {
@ -53,11 +53,11 @@ display_msg:
}
else {
// For console application we print the info to console
printf("Assertion failed: %s\n", cond);
printf(" Function: %s\n", func);
printf(" File: %s\n", file);
printf(" Line: %d\n", line);
printf("Trace:\n");
// printf("Assertion failed: %s\n", cond);
// printf(" Function: %s\n", func);
// printf(" File: %s\n", file);
// printf(" Line: %d\n", line);
// printf("Trace:\n");
_print_stack_trace();
abort();
}

View File

@ -9,7 +9,7 @@ void __security_init_cookie() {
void __security_check_cookie(u64 retrieved) {
if(__security_cookie != retrieved) {
printf("Bro you've got a buffer overrun\n");
// printf("Bro you've got a buffer overrun\n");
abort();
}
}

View File

@ -11,7 +11,7 @@ _Noreturn void mainCRTStartup() {
_setup_eh();
_setup_heap();
_setup_timer();
_setup_io();
_io_init();
__security_init_cookie();
srand(0);
@ -28,7 +28,7 @@ _Noreturn void mainCRTStartup() {
_setup_eh();
_setup_heap();
_setup_timer();
_setup_io();
_io_init();
__security_init_cookie();
srand(0);

View File

@ -34,7 +34,7 @@ _Noreturn void exit(int status) {
while(atexit_func_count--) {
atexit_funcs[atqexit_func_count]();
}
_close_io();
_io_close();
_Exit(status);
}

View File

@ -1,42 +1,37 @@
enum stream_width_t {
STREAM_CHAR_UNSET,
STREAM_CHAR_NARROW,
STREAM_CHAR_WIDE,
} typedef stream_width_t;
enum FileMode {
MODE_INPUT,
MODE_OUTPUT,
MODE_UPDATE,
} typedef FileMode;
enum stream_io_mode_t {
STREAM_INPUT,
STREAM_OUTPUT,
STREAM_UPDATE,
} typedef stream_io_mode_t;
enum FileType {
FILE_BINARY,
FILE_TEXT,
} typedef FileType;
enum stream_bt_mode_t {
STREAM_BINARY,
STREAM_TEXT,
} typedef stream_bt_mode_t;
struct stream_buffer_t typedef stream_buffer_t;
struct stream_buffer_t {
int is_internal;
int mode;
struct FileBuffer typedef FileBuffer;
struct FileBuffer {
int is_internal;
int mode;
size_t size;
void *data;
size_t written;
};
struct FILE {
HANDLE handle;
stream_width_t char_width; // This technically needs not be stored
mbstate_t mbstate;
stream_buffer_t buffer;
stream_io_mode_t io_mode;
stream_bt_mode_t bt_mode;
int eof;
int err;
mtx_t lock;
FILE *prev;
FILE *next;
HANDLE handle;
mbstate_t mbstate;
FileBuffer buffer;
FileMode io_mode;
FileType bt_mode;
int eof;
int err;
mtx_t lock;
bool temp;
char *temp_name;
FILE *prev;
FILE *next;
};
FILE *stdout;
@ -46,108 +41,121 @@ FILE *stderr;
// We hold a linked list of all file streams in order to flush all the buffers
// after the program terminates. It might be not a good idea to store all the
// files into this linked list, but for now performance is not a concern.
static FILE *streams_to_close = NULL;
static void close_list_add(FILE *stream) {
if(streams_to_close != NULL) {
streams_to_close->next = stream;
stream->prev = streams_to_close;
static FILE *_file_tracker = NULL;
static void _file_track(FILE *stream) {
if(_file_tracker != NULL) {
_file_tracker->next = stream;
stream->prev = _file_tracker;
stream->next = NULL;
streams_to_close = stream;
_file_tracker = stream;
}
else {
streams_to_close = stream;
_file_tracker = stream;
stream->prev = NULL;
stream->next = NULL;
}
}
static void close_list_remove(FILE *stream) {
static void _file_untrack(FILE *stream) {
FILE *prev = stream->prev;
FILE *next = stream->next;
if(prev != NULL) prev->next = next;
if(next != NULL) next->prev = prev;
if(next == NULL) streams_to_close = prev;
if(next == NULL) _file_tracker = prev;
}
static inline void init_stream(
FILE *stream,
HANDLE handle,
stream_io_mode_t io_mode,
stream_bt_mode_t bt_mode
) {
// Multithreaded access
static inline void _file_lock_init(FILE *stream) {
mtx_init(&stream->lock, mtx_recursive);
}
static inline void _file_lock_destroy(FILE *stream) {
mtx_destroy(&stream->lock);
}
static inline void _file_lock(FILE *stream) {
mtx_lock(&stream->lock);
}
static inline void _file_unlock(FILE *stream) {
mtx_unlock(&stream->lock);
}
// Managing file handles
static inline FILE *_file_create(HANDLE handle, FileMode io_mode, FileType bt_mode) {
FILE *stream = calloc(1, sizeof(FILE));
if(stream == NULL) {
return NULL;
}
stream->handle = handle;
stream->char_width = STREAM_CHAR_UNSET;
stream->mbstate = (mbstate_t){0};
stream->buffer.mode = _IONBF;
stream->io_mode = io_mode;
stream->bt_mode = bt_mode;
stream->eof = 0;
stream->err = 0;
}
static inline FILE *create_stream(
HANDLE handle,
stream_io_mode_t io_mode,
stream_bt_mode_t bt_mode
) {
FILE *stream = malloc(sizeof(FILE));
if(stream == NULL) return NULL;
init_stream(stream, handle, io_mode, bt_mode);
mtx_init(&stream->lock, mtx_recursive);
close_list_add(stream);
_file_lock_init(stream);
_file_track(stream);
return stream;
}
static inline void delete_stream(FILE *stream) {
mtx_t lock = stream->lock;
mtx_lock(&lock);
static inline void _file_close(FILE *stream) {
_file_lock(stream);
CloseHandle(stream->handle);
close_list_remove(stream);
_file_untrack(stream);
_file_unlock(stream);
_file_lock_destroy(stream);
free(stream);
mtx_unlock(&lock);
mtx_destroy(&lock);
}
static void _setup_io() {
static void _io_init() {
HANDLE hstdout = GetStdHandle(STD_OUTPUT_HANDLE);
HANDLE hstderr = GetStdHandle(STD_ERROR_HANDLE);
HANDLE hstdin = GetStdHandle(STD_INPUT_HANDLE);
stdout = create_stream(hstdout, STREAM_UPDATE, STREAM_TEXT);
stderr = create_stream(hstderr, STREAM_UPDATE, STREAM_TEXT);
stdin = create_stream(hstdin, STREAM_INPUT, STREAM_BINARY);
stdout = _file_create(hstdout, MODE_UPDATE, FILE_TEXT);
stderr = _file_create(hstderr, MODE_UPDATE, FILE_TEXT);
stdin = _file_create(hstdin, MODE_INPUT, FILE_BINARY);
char *in_buf = calloc(BUFSIZ, sizeof(char));
char *out_buf = calloc(BUFSIZ, sizeof(char));
stdin->buffer = (stream_buffer_t){1, _IOLBF, BUFSIZ, in_buf};
stdout->buffer = (stream_buffer_t){1, _IOLBF, BUFSIZ, out_buf};
stderr->buffer = (stream_buffer_t){1, _IONBF, 0, NULL};
stdin->buffer = (FileBuffer){1, _IOLBF, BUFSIZ, in_buf};
stdout->buffer = (FileBuffer){1, _IOLBF, BUFSIZ, out_buf};
stderr->buffer = (FileBuffer){1, _IONBF, 0, NULL};
SetConsoleCP(CP_UTF8); // maybe will work someday
SetConsoleCP(CP_UTF8); // Maybe it will work someday
SetConsoleOutputCP(CP_UTF8);
}
int win_parse_mode(
char const *mode,
stream_io_mode_t *pio_mode,
stream_bt_mode_t *pbt_mode,
DWORD *paccess,
DWORD *pshare,
DWORD *pdisp
) {
static void _io_close() {
while(_file_tracker != NULL) {
FILE *stream = _file_tracker;
fclose(stream);
}
}
// File mode parsing
struct WindowsMode typedef WindowsMode;
struct WindowsMode {
DWORD access;
DWORD share;
DWORD disp;
};
static int _mode_parse(char const *mode, FileMode *pio_mode, FileType *pbt_mode, WindowsMode *win_mode) {
DWORD access = 0;
DWORD share = 0;
DWORD disp = 0;
stream_io_mode_t io_mode = 0;
stream_bt_mode_t bt_mode = 0;
FileMode io_mode = 0;
FileType bt_mode = 0;
int flag_p = 0;
int flag_b = 0;
int flag_x = 0;
switch(*mode++) {
case 'r': io_mode = STREAM_INPUT; break;
case 'w': io_mode = STREAM_OUTPUT; break;
case 'a': io_mode = STREAM_UPDATE; break;
case 'r': io_mode = MODE_INPUT; break;
case 'w': io_mode = MODE_OUTPUT; break;
case 'a': io_mode = MODE_UPDATE; break;
default: return 0;
}
while(*mode) switch(*mode++) {
@ -156,15 +164,14 @@ int win_parse_mode(
case 'x': flag_x = 1; break;
default: return 0;
}
bt_mode = flag_b? STREAM_BINARY : STREAM_TEXT;
// Not sure about the sharing modes
bt_mode = flag_b? FILE_BINARY : FILE_TEXT;
switch(io_mode) {
case STREAM_INPUT: {
case MODE_INPUT: {
access = GENERIC_READ | (flag_p? GENERIC_WRITE : 0);
share = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
disp = OPEN_EXISTING;
} break;
case STREAM_OUTPUT: {
case MODE_OUTPUT: {
access = GENERIC_WRITE | (flag_p? GENERIC_READ : 0);
share = 0;
disp = CREATE_ALWAYS;
@ -172,37 +179,82 @@ int win_parse_mode(
disp = CREATE_NEW;
}
} break;
case STREAM_UPDATE: {
case MODE_UPDATE: {
access = GENERIC_READ | GENERIC_WRITE;
share = 0;
disp = OPEN_ALWAYS;
} break;
}
*paccess = access;
*pshare = share;
*pdisp = disp;
win_mode->access = access;
win_mode->share = share;
win_mode->disp = disp;
*pio_mode = io_mode;
*pbt_mode = bt_mode;
return 1;
}
FILE *fopen(const char *restrict name, const char *restrict mode) {
DWORD access;
DWORD share;
DWORD disp;
DWORD flags = FILE_FLAG_WRITE_THROUGH;
stream_io_mode_t io_mode;
stream_bt_mode_t bt_mode;
if(!win_parse_mode(mode, &io_mode, &bt_mode, &access, &share, &disp)) {
// Operations on files
int remove(const char *filename) {
BOOL ok = DeleteFileA(filename);
return !ok;
}
int rename(const char *old, const char *new) {
BOOL ok = MoveFileA(old, new);
return !ok;
}
// Opening/closing files
char *tmpnam(char *s) {
static char internal_buffer[L_tmpnam];
char *buffer;
if(s != NULL) {
buffer = s;
}
else {
buffer = &internal_buffer[0];
}
UINT num = GetTempFileNameA(".", ".t_", 0, buffer);
if(num == 0) {
return NULL;
}
else {
return buffer;
}
}
FILE *tmpfile(void) {
char *file_name = malloc(L_tmpnam);
UINT num = GetTempFileNameA(".", ".t_", 0, &file_name[0]);
if(!num) {
return NULL;
}
FILE *tmp_file = fopen(&file_name[0], "wb+");
tmp_file->temp = true;
tmp_file->temp_name = file_name;
return tmp_file;
}
FILE *fopen(const char *restrict name, const char *restrict mode) {
WindowsMode win_mode;
DWORD flags = FILE_FLAG_WRITE_THROUGH;
FileMode io_mode;
FileType bt_mode;
if(!_mode_parse(mode, &io_mode, &bt_mode, &win_mode)) {
return NULL;
}
DWORD access = win_mode.access;
DWORD share = win_mode.share;
DWORD disp = win_mode.disp;
HANDLE handle = CreateFileA(name, access, share, NULL, disp, flags, NULL);
if(handle == INVALID_HANDLE_VALUE) {
return NULL;
}
FILE *stream = create_stream(handle, io_mode, bt_mode);
FILE *stream = _file_create(handle, io_mode, bt_mode);
void *buffer_data = malloc(BUFSIZ);
stream->buffer = (stream_buffer_t) {1, _IOFBF, BUFSIZ, buffer_data};
stream->buffer = (FileBuffer) {1, _IOFBF, BUFSIZ, buffer_data};
return stream;
}
@ -211,15 +263,16 @@ FILE *freopen(const char *restrict name, const char *restrict mode, FILE *restri
return NULL;
}
fflush(stream);
DWORD access;
DWORD share;
DWORD disp;
WindowsMode win_mode;
DWORD flags = FILE_FLAG_WRITE_THROUGH;
stream_io_mode_t io_mode;
stream_bt_mode_t bt_mode;
if(!win_parse_mode(mode, &io_mode, &bt_mode, &access, &share, &disp)) {
FileMode io_mode;
FileType bt_mode;
if(!_mode_parse(mode, &io_mode, &bt_mode, &win_mode)) {
return NULL;
}
DWORD access = win_mode.access;
DWORD share = win_mode.share;
DWORD disp = win_mode.disp;
if(name == NULL) {
HANDLE handle = ReOpenFile(stream->handle, access, share, flags);
if(handle == INVALID_HANDLE_VALUE) {
@ -232,15 +285,14 @@ FILE *freopen(const char *restrict name, const char *restrict mode, FILE *restri
if(handle == INVALID_HANDLE_VALUE) {
return NULL;
}
init_stream(stream, handle, io_mode, bt_mode);
*stream = (FILE) {0};
stream->handle = handle;
stream->io_mode = io_mode;
stream->bt_mode = bt_mode;
}
return stream;
}
FILE *tmpfile(void) {
return NULL;
}
int fclose(FILE *stream) {
if(fflush(stream) == EOF) {
return EOF;
@ -251,17 +303,63 @@ int fclose(FILE *stream) {
if(!CloseHandle(stream->handle)) {
return EOF;
}
if(stream->temp) {
BOOL err = DeleteFileA(stream->temp_name);
free(stream->temp_name);
return err;
}
return 0;
}
static void _close_io() {
while(streams_to_close != NULL) {
FILE *stream = streams_to_close;
fflush(stream);
delete_stream(stream);
// Buffering
int setvbuf(FILE *restrict stream, char *restrict ptr, int mode, size_t size) {
if(mode != _IOFBF && mode != _IOLBF && mode != _IONBF) {
return 1;
}
_file_lock(stream);
FileBuffer *buffer = &stream->buffer;
buffer->mode = mode;
if(ptr == NULL) {
buffer->data = realloc(buffer->data, size);
buffer->size = size;
}
else {
buffer->data = ptr;
buffer->size = size;
}
_file_unlock(stream);
return 0;
}
void setbuf(FILE *restrict stream, char *restrict buf) {
if(buf == NULL) {
setvbuf(stream, NULL, _IONBF, 0);
}
else {
setvbuf(stream, buf, _IOFBF, BUFSIZ);
}
}
int fflush(FILE *stream) {
_file_lock(stream);
int res = 0;
FileBuffer *buffer = &stream->buffer;
void *data = buffer->data;
size_t size = buffer->written;
DWORD bytes_written;
BOOL ok = WriteFile(stream->handle, data, size, &bytes_written, NULL);
if(!ok) {
res = EOF;
stream->eof = 1;
}
buffer->written = 0;
_file_unlock(stream);
return res;
}
// Errors
int feof(FILE *stream) {
return stream->eof;
}
@ -276,57 +374,14 @@ void clearerr(FILE *stream) {
}
void perror(char const *s) {
printf("%s: %s\n", s, strerror(errno));
// printf("%s: %s\n", s, strerror(errno));
}
int setvbuf(FILE *restrict stream, char *restrict ptr, int mode, size_t size) {
if(mode != _IOFBF && mode != _IOLBF && mode != _IONBF) {
return 1;
}
mtx_lock(&stream->lock);
stream_buffer_t *buffer = &stream->buffer;
buffer->mode = mode;
if(ptr == NULL) {
buffer->data = realloc(buffer->data, size);
buffer->size = size;
}
else {
buffer->data = ptr;
buffer->size = size;
}
mtx_unlock(&stream->lock);
return 0;
}
void setbuf(FILE *restrict stream, char *restrict buf) {
if(buf == NULL) {
setvbuf(stream, NULL, _IONBF, 0);
}
else {
setvbuf(stream, buf, _IOFBF, BUFSIZ);
}
}
int fflush(FILE *stream) {
mtx_lock(&stream->lock);
int res = 0;
stream_buffer_t *buffer = &stream->buffer;
void *data = buffer->data;
size_t size = buffer->written;
DWORD bytes_written;
BOOL ok = WriteFile(stream->handle, data, size, &bytes_written, NULL);
if(!ok) {
res = EOF;
stream->eof = 1;
}
buffer->written = 0;
mtx_unlock(&stream->lock);
return res;
}
// File reads/writes
int fputc(int c, FILE *stream) {
mtx_lock(&stream->lock);
stream_buffer_t *buffer = &stream->buffer;
_file_lock(stream);
FileBuffer *buffer = &stream->buffer;
int res = c;
if(buffer->mode == _IONBF) {
unsigned char str[1] = {c};
@ -335,7 +390,7 @@ int fputc(int c, FILE *stream) {
if(!ok) {
res = EOF;
stream->err = 1;
goto cum;
goto end;
}
}
@ -349,19 +404,19 @@ int fputc(int c, FILE *stream) {
}
if(needs_flush) {
if(fflush(stream) == EOF) {
goto cum;
goto end;
}
}
}
cum:
mtx_unlock(&stream->lock);
end:
_file_unlock(stream);
return res;
}
int fgetc(FILE *stream) {
mtx_lock(&stream->lock);
_file_lock(stream);
int res = 0;
stream_buffer_t *buffer = &stream->buffer;
FileBuffer *buffer = &stream->buffer;
int read_from_disk = 1;
if(buffer->mode != _IONBF) {
unsigned char *data = buffer->data;
@ -377,95 +432,47 @@ int fgetc(FILE *stream) {
if(bytes_read != 1) {
res = EOF;
stream->eof = 1;
goto cum;
goto end;
}
if(!ok) {
res = EOF;
goto cum;
goto end;
}
res = buf[0];
}
cum:
mtx_unlock(&stream->lock);
end:
_file_unlock(stream);
return res;
}
int ungetc(int c, FILE *stream) {
mtx_lock(&stream->lock);
_file_lock(stream);
int res;
stream_buffer_t *buffer = &stream->buffer;
FileBuffer *buffer = &stream->buffer;
if(buffer->mode == _IONBF) {
res = EOF;
goto cum;
goto end;
}
else {
if(c == EOF) {
res = EOF;
goto cum;
goto end;
}
if(buffer->written == buffer->size) {
res = EOF;
goto cum;
goto end;
}
unsigned char *data = buffer->data;
data[buffer->written++] = (unsigned char)c;
res = c;
}
cum:
mtx_unlock(&stream->lock);
end:
_file_unlock(stream);
return res;
}
int fgetpos(FILE *restrict stream, fpos_t *restrict pos) {
LONG pos_hi = 0;
DWORD pos_lo = SetFilePointer(stream->handle, 0, &pos_hi, FILE_CURRENT);
if(pos_lo == INVALID_SET_FILE_POINTER) {
return 1;
}
int64_t offset = ((int64_t)pos_hi << 32) | (int64_t)pos_lo;
pos->offset = offset;
pos->mbstate = stream->mbstate;
return 0;
}
int fseek(FILE *stream, long int offset, int whence) {
// Note(bumbread): the SEEK_SET, SEEK_CUR and SEEK_END are defined to match
// Windows' constants, so no conversion is requierd between them.
LONG pos_hi = 0;
DWORD pos_lo = SetFilePointer(stream->handle, offset, &pos_hi, whence);
if(pos_lo == INVALID_SET_FILE_POINTER) {
return -1L;
}
return 0;
}
int fsetpos(FILE *stream, const fpos_t *pos) {
LONG pos_hi = pos->offset >> 32;
LONG pos_lo = (LONG)(pos->offset & 0xffffffff);
DWORD status = SetFilePointer(stream->handle, pos_lo, &pos_hi, FILE_BEGIN);
if(status == INVALID_SET_FILE_POINTER) {
return 1;
}
stream->mbstate = pos->mbstate;
return 0;
}
long int ftell(FILE *stream) {
LONG pos_hi = 0;
DWORD pos_lo = SetFilePointer(stream->handle, 0, &pos_hi, FILE_CURRENT);
if(pos_lo == INVALID_SET_FILE_POINTER) {
return -1L;
}
int64_t offset = ((int64_t)pos_hi << 32) | (int64_t)pos_lo;
return offset;
}
void rewind(FILE *stream) {
fseek(stream, 0, SEEK_SET);
}
size_t fwrite(void const *restrict buffer, size_t size, size_t count, FILE *restrict stream) {
mtx_lock(&stream->lock);
_file_lock(stream);
unsigned char const *bytes = (unsigned char const*)buffer;
size_t num_written;
for(num_written = 0; num_written < count; ++num_written) {
@ -478,12 +485,12 @@ size_t fwrite(void const *restrict buffer, size_t size, size_t count, FILE *rest
bytes += size;
}
end:
mtx_unlock(&stream->lock);
_file_unlock(stream);
return num_written;
}
size_t fread(void *restrict buffer, size_t size, size_t count, FILE *restrict stream) {
mtx_lock(&stream->lock);
_file_lock(stream);
unsigned char *bytes = (unsigned char *)buffer;
size_t num_read;
for(num_read = 0; num_read < count; ++num_read) {
@ -497,7 +504,7 @@ size_t fread(void *restrict buffer, size_t size, size_t count, FILE *restrict st
bytes += size;
}
end:
mtx_unlock(&stream->lock);
_file_unlock(stream);
return num_read;
}
@ -517,7 +524,7 @@ char *fgets(char *restrict str, int count, FILE *restrict stream) {
str[0] = 0;
return str;
}
mtx_lock(&stream->lock);
_file_lock(stream);
int i;
for(i = 0; i < count-1; ++i) {
int c = fgetc(stream);
@ -535,12 +542,12 @@ char *fgets(char *restrict str, int count, FILE *restrict stream) {
}
}
str[i] = 0;
mtx_unlock(&stream->lock);
_file_unlock(stream);
return str;
}
int fputs(char const *str, FILE *stream) {
mtx_lock(&stream->lock);
_file_lock(stream);
int res = 0;
while(*str) {
int c = fputc(*str++, stream);
@ -549,7 +556,7 @@ int fputs(char const *str, FILE *stream) {
break;
}
}
mtx_unlock(&stream->lock);
_file_unlock(stream);
return res;
}
@ -562,3 +569,55 @@ int puts(char const *str) {
char *gets(char *str) {
return fgets(str, 0x7fffffff, stdin);
}
// File positioning:
int fgetpos(FILE *restrict stream, fpos_t *restrict pos) {
LONG pos_hi = 0;
DWORD pos_lo = SetFilePointer(stream->handle, 0, &pos_hi, FILE_CURRENT);
if(pos_lo == INVALID_SET_FILE_POINTER) {
return 1;
}
int64_t offset = ((int64_t)pos_hi << 32) | (int64_t)pos_lo;
pos->offset = offset;
pos->mbstate.leftover = stream->mbstate.leftover;
pos->mbstate.high_surrogate = stream->mbstate.high_surrogate;
return 0;
}
int fseek(FILE *stream, long int offset, int whence) {
// Note(bumbread): the SEEK_SET, SEEK_CUR and SEEK_END are defined to match
// the Windows constants, so no conversion is requierd between them.
LONG pos_hi = 0;
DWORD pos_lo = SetFilePointer(stream->handle, offset, &pos_hi, whence);
if(pos_lo == INVALID_SET_FILE_POINTER) {
return -1L;
}
return 0;
}
int fsetpos(FILE *stream, const fpos_t *pos) {
LONG pos_hi = pos->offset >> 32;
LONG pos_lo = (LONG)(pos->offset & 0xffffffff);
DWORD status = SetFilePointer(stream->handle, pos_lo, &pos_hi, FILE_BEGIN);
if(status == INVALID_SET_FILE_POINTER) {
return 1;
}
stream->mbstate.leftover = pos->mbstate.leftover;
stream->mbstate.high_surrogate = pos->mbstate.high_surrogate;
return 0;
}
long int ftell(FILE *stream) {
LONG pos_hi = 0;
DWORD pos_lo = SetFilePointer(stream->handle, 0, &pos_hi, FILE_CURRENT);
if(pos_lo == INVALID_SET_FILE_POINTER) {
return -1L;
}
int64_t offset = ((int64_t)pos_hi << 32) | (int64_t)pos_lo;
return offset;
}
void rewind(FILE *stream) {
fseek(stream, 0, SEEK_SET);
}

View File

@ -10,5 +10,4 @@
static void _setup_timer(void);
static void _setup_eh();
static void _setup_heap();
static void _setup_io();
static void _close_io();
static void _io_close();

View File

@ -2,29 +2,10 @@
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
int main(void)
{
// prepare a file holding 4 values of type char
enum {SIZE = 4};
FILE* fp = fopen("test.bin", "wb");
assert(fp);
fputc('a', fp);
fputc('b', fp);
fputc('d', fp);
fputc('c', fp);
fclose(fp);
// demo using fsetpos to return to the beginning of a file
fp = fopen("test.bin", "rb");
fpos_t pos;
int c = fgetc(fp);
printf("First value in the file: %c\n", c);
fgetpos(fp, &pos);
c = fgetc(fp);
printf("Second value in the file: %c\n", c);
fsetpos(fp,&pos);
c = fgetc(fp);
printf("Second value in the file again: %c\n", c);
fclose(fp);
int main(void) {
FILE *tmp = tmpfile();
fputc('a', tmp);
fclose(tmp);
return 0;
}