mirror of https://github.com/flysand7/ciabatta.git
stdio.h the beginning
This commit is contained in:
parent
88ef3bf81f
commit
7cb9dc133f
19
inc/stdio.h
19
inc/stdio.h
|
@ -1,14 +1,10 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
|
||||
typedef struct FILE FILE;
|
||||
typedef int64_t fpos_t;
|
||||
|
||||
typedef struct div_t div_t;
|
||||
typedef struct ldiv_t ldiv_t;
|
||||
typedef struct lldiv_t lldiv_t;
|
||||
typedef size_t fpos_t;
|
||||
|
||||
#if !defined(NULL)
|
||||
#define NULL ((void *)0)
|
||||
|
@ -26,15 +22,12 @@ typedef struct lldiv_t lldiv_t;
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#define _IOFBF 0x0000
|
||||
#define _IOLBF 0x0040
|
||||
#define _IONBF 0x0004
|
||||
|
||||
#define _IONBF 0
|
||||
#define _IOFBF 1
|
||||
#define _IOLBF 2
|
||||
#define BUFSIZ 512
|
||||
|
||||
#define EOF (-1)
|
||||
|
||||
#define FOPEN_MAX 20
|
||||
#define FOPEN_MAX 1024
|
||||
|
||||
#ifdef _os_win
|
||||
#define FILENAME_MAX 260
|
||||
|
|
|
@ -5,6 +5,10 @@ typedef struct mbstate_t mbstate_t;
|
|||
typedef uint16_t char16_t;
|
||||
typedef uint32_t char32_t;
|
||||
|
||||
struct mbstate_t {
|
||||
char filler[4];
|
||||
};
|
||||
|
||||
size_t mbrtoc16(char16_t * restrict pc16, const char * restrict s, size_t n, mbstate_t * restrict ps);
|
||||
size_t c16rtomb(char * restrict s, char16_t c16, mbstate_t * restrict ps);
|
||||
size_t mbrtoc32(char32_t * restrict pc32, const char * restrict s, size_t n, mbstate_t * restrict ps);
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
// On linux this will be UTF-32, on windows it's UTF-16 (or maybe UCS-2?)
|
||||
typedef struct mbstate_t mbstate_t;
|
||||
typedef wchar_t wint_t;
|
||||
|
||||
struct mbstate_t {
|
||||
char filler[4];
|
||||
};
|
||||
|
||||
#define WCHAR_MIN 0x0000
|
||||
#define WCHAR_MAX 0xffff
|
||||
|
||||
|
|
|
@ -10,3 +10,4 @@
|
|||
void _setup_timer(void);
|
||||
void _setup_eh();
|
||||
void _setup_heap();
|
||||
void _setup_io();
|
||||
|
|
|
@ -71,15 +71,11 @@ static char **get_command_args(int *argc_ptr) {
|
|||
|
||||
|
||||
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_heap();
|
||||
_setup_timer();
|
||||
_setup_io();
|
||||
|
||||
// Set-up CRT stuff
|
||||
srand(0);
|
||||
|
@ -145,3 +141,45 @@ char *getenv(const char *name) {
|
|||
GetEnvironmentVariable(name, env_string, env_length);
|
||||
return env_string;
|
||||
}
|
||||
|
||||
int system(const char* string) {
|
||||
int wchars_required = MultiByteToWideChar(65001, 0, string, -1, NULL, 0);
|
||||
wchar_t* cmd_line = malloc(sizeof(L"cmd.exe ") + (wchars_required * sizeof(wchar_t)));
|
||||
if (cmd_line == NULL) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
memcpy(cmd_line, L"cmd.exe ", sizeof(L"cmd.exe "));
|
||||
MultiByteToWideChar(65001, 0, string, -1, cmd_line + sizeof("cmd.exe ") - 1, wchars_required);
|
||||
|
||||
STARTUPINFOW si = {
|
||||
.cb = sizeof(STARTUPINFOW),
|
||||
.dwFlags = STARTF_USESTDHANDLES,
|
||||
.hStdInput = GetStdHandle(STD_INPUT_HANDLE),
|
||||
.hStdError = GetStdHandle(STD_ERROR_HANDLE),
|
||||
.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE)
|
||||
};
|
||||
PROCESS_INFORMATION pi = {};
|
||||
|
||||
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,58 +1,147 @@
|
|||
|
||||
#include <win.h>
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <win.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <threads.h>
|
||||
#include <uchar.h>
|
||||
|
||||
enum str_type {
|
||||
STR_R,
|
||||
STR_W,
|
||||
STR_A,
|
||||
} typedef str_type;
|
||||
|
||||
enum str_flags {
|
||||
STR_U = 1,
|
||||
STR_X = 2,
|
||||
STR_B = 4,
|
||||
} typedef str_flags;
|
||||
|
||||
enum str_mode {
|
||||
STR_BIN,
|
||||
STR_TEXT,
|
||||
} typedef str_mode;
|
||||
|
||||
// It's just mapped directly to HANDLE
|
||||
struct FILE {
|
||||
int unused;
|
||||
HANDLE handle;
|
||||
char *name;
|
||||
str_type type;
|
||||
str_flags flags;
|
||||
str_mode mode;
|
||||
int buftype;
|
||||
size_t bufsize;
|
||||
char *buffer;
|
||||
mbstate_t mbstate;
|
||||
mtx_t lock;
|
||||
FILE *prev;
|
||||
FILE *next;
|
||||
};
|
||||
|
||||
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;
|
||||
// Linked list because I'm based and you can't say I'm wrong
|
||||
static FILE *file_list_last = NULL;
|
||||
|
||||
static inline FILE *new_file(
|
||||
HANDLE handle,
|
||||
char *name,
|
||||
str_type type,
|
||||
str_flags flags,
|
||||
int mode,
|
||||
int buftype,
|
||||
size_t bufsize,
|
||||
char *buffer
|
||||
) {
|
||||
FILE *file = malloc(sizeof(FILE));
|
||||
if(file == NULL) return NULL;
|
||||
file->handle = handle;
|
||||
file->name = name; // TODO: strdup this
|
||||
file->type = type;
|
||||
file->flags = flags;
|
||||
file->mode = mode;
|
||||
file->mbstate = (mbstate_t){0};
|
||||
mtx_init(&file->lock, mtx_recursive);
|
||||
if(file_list_last != NULL) {
|
||||
file_list_last->next = file;
|
||||
file->prev = file_list_last;
|
||||
file->next = NULL;
|
||||
}
|
||||
else {
|
||||
file_list_last = file;
|
||||
file->prev = NULL;
|
||||
file->next = NULL;
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
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;
|
||||
static inline void dispose_file(FILE *file) {
|
||||
mtx_t lock = file->lock;
|
||||
mtx_lock(&lock);
|
||||
// Only close the file if it's not a standard handle
|
||||
if(file->name) {
|
||||
CloseHandle(file->handle);
|
||||
//TODO: free(file->name);
|
||||
}
|
||||
// TODO: flush streams
|
||||
FILE *prev = file->prev;
|
||||
FILE *next = file->next;
|
||||
if(prev != NULL) prev->next = next;
|
||||
if(next != NULL) next->prev = prev;
|
||||
if(next == NULL) file_list_last = prev;
|
||||
free(file);
|
||||
mtx_unlock(&lock);
|
||||
}
|
||||
|
||||
// Wait until child process exits.
|
||||
WaitForSingleObject(pi.hProcess, INFINITE);
|
||||
void _setup_io() {
|
||||
HANDLE hstdout = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
HANDLE hstderr = GetStdHandle(STD_ERROR_HANDLE);
|
||||
HANDLE hstdin = GetStdHandle(STD_INPUT_HANDLE);
|
||||
|
||||
DWORD exit_code;
|
||||
if (!GetExitCodeProcess(pi.hProcess, &exit_code)) {
|
||||
goto error;
|
||||
char *out_buf = calloc(BUFSIZ, sizeof(char));
|
||||
char *err_buf = out_buf;
|
||||
if(hstdout != hstderr) {
|
||||
err_buf = calloc(BUFSIZ, sizeof(char));
|
||||
}
|
||||
|
||||
// Close process and thread handles.
|
||||
CloseHandle(pi.hProcess);
|
||||
CloseHandle(pi.hThread);
|
||||
free(cmd_line);
|
||||
return exit_code;
|
||||
|
||||
error:
|
||||
free(cmd_line);
|
||||
return -1;
|
||||
stdout = new_file(hstdout, NULL, STR_W, 0, 0, _IOLBF, BUFSIZ, out_buf);
|
||||
stderr = new_file(hstderr, NULL, STR_W, 0, 0, _IOLBF, BUFSIZ, err_buf);
|
||||
stdin = new_file(hstdin, NULL, STR_R, 0, 0, _IONBF, 0, NULL);
|
||||
}
|
||||
|
||||
int setvbuf(
|
||||
FILE *restrict stream,
|
||||
char *restrict buf,
|
||||
int mode,
|
||||
size_t size
|
||||
) {
|
||||
if(mode == _IONBF) {
|
||||
stream->buftype = mode;
|
||||
stream->buffer = NULL;
|
||||
stream->bufsize = 0;
|
||||
return 0;
|
||||
}
|
||||
if(mode != _IOFBF && mode != _IOLBF)
|
||||
return 1;
|
||||
if(buf == NULL && size != 0) {
|
||||
buf = malloc(size);
|
||||
}
|
||||
if(size == 0) {
|
||||
buf = NULL;
|
||||
mode = _IONBF;
|
||||
}
|
||||
stream->buftype = mode;
|
||||
stream->buffer = buf;
|
||||
stream->bufsize = size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void setbuf(FILE *restrict stream, char *restrict buf) {
|
||||
if(buf != NULL)
|
||||
setvbuf(stream, buf, _IOFBF, BUFSIZ);
|
||||
else
|
||||
setvbuf(stream, buf, _IONBF, BUFSIZ);
|
||||
}
|
||||
|
|
5
todo
5
todo
|
@ -1,4 +1,8 @@
|
|||
|
||||
general:
|
||||
* Start writing documentation concerning various implementation defined
|
||||
behaviours of the library.
|
||||
|
||||
locale.h:
|
||||
Make other locales actually work
|
||||
|
||||
|
@ -36,6 +40,7 @@ stdlib.h:
|
|||
|
||||
threads.h:
|
||||
Make _Thread_local work on windows
|
||||
Verify the mtx_recursive goes ok. Also change win_stdio.c accordingly.
|
||||
TODO: add todo items
|
||||
|
||||
tgmath.h:
|
||||
|
|
Loading…
Reference in New Issue