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
|
#pragma once
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
typedef struct FILE FILE;
|
typedef struct FILE FILE;
|
||||||
typedef int64_t fpos_t;
|
typedef size_t fpos_t;
|
||||||
|
|
||||||
typedef struct div_t div_t;
|
|
||||||
typedef struct ldiv_t ldiv_t;
|
|
||||||
typedef struct lldiv_t lldiv_t;
|
|
||||||
|
|
||||||
#if !defined(NULL)
|
#if !defined(NULL)
|
||||||
#define NULL ((void *)0)
|
#define NULL ((void *)0)
|
||||||
|
@ -26,15 +22,12 @@ typedef struct lldiv_t lldiv_t;
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define _IOFBF 0x0000
|
#define _IONBF 0
|
||||||
#define _IOLBF 0x0040
|
#define _IOFBF 1
|
||||||
#define _IONBF 0x0004
|
#define _IOLBF 2
|
||||||
|
|
||||||
#define BUFSIZ 512
|
#define BUFSIZ 512
|
||||||
|
|
||||||
#define EOF (-1)
|
#define EOF (-1)
|
||||||
|
#define FOPEN_MAX 1024
|
||||||
#define FOPEN_MAX 20
|
|
||||||
|
|
||||||
#ifdef _os_win
|
#ifdef _os_win
|
||||||
#define FILENAME_MAX 260
|
#define FILENAME_MAX 260
|
||||||
|
|
|
@ -5,6 +5,10 @@ typedef struct mbstate_t mbstate_t;
|
||||||
typedef uint16_t char16_t;
|
typedef uint16_t char16_t;
|
||||||
typedef uint32_t char32_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 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 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);
|
size_t mbrtoc32(char32_t * restrict pc32, const char * restrict s, size_t n, mbstate_t * restrict ps);
|
||||||
|
|
|
@ -1,15 +1,18 @@
|
||||||
|
|
||||||
#pragma once
|
#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 struct mbstate_t mbstate_t;
|
||||||
typedef wchar_t wint_t;
|
typedef wchar_t wint_t;
|
||||||
|
|
||||||
|
struct mbstate_t {
|
||||||
|
char filler[4];
|
||||||
|
};
|
||||||
|
|
||||||
#define WCHAR_MIN 0x0000
|
#define WCHAR_MIN 0x0000
|
||||||
#define WCHAR_MAX 0xffff
|
#define WCHAR_MAX 0xffff
|
||||||
|
|
||||||
#ifndef WEOF
|
#ifndef WEOF
|
||||||
#define WEOF 0
|
#define WEOF 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int fwprintf(FILE * restrict stream, const wchar_t * restrict format, ...);
|
int fwprintf(FILE * restrict stream, const wchar_t * restrict format, ...);
|
||||||
|
|
|
@ -10,3 +10,4 @@
|
||||||
void _setup_timer(void);
|
void _setup_timer(void);
|
||||||
void _setup_eh();
|
void _setup_eh();
|
||||||
void _setup_heap();
|
void _setup_heap();
|
||||||
|
void _setup_io();
|
||||||
|
|
|
@ -71,15 +71,11 @@ static char **get_command_args(int *argc_ptr) {
|
||||||
|
|
||||||
|
|
||||||
void mainCRTStartup() {
|
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
|
// Set-up some platform stuff
|
||||||
_setup_heap();
|
|
||||||
_setup_eh();
|
_setup_eh();
|
||||||
|
_setup_heap();
|
||||||
_setup_timer();
|
_setup_timer();
|
||||||
|
_setup_io();
|
||||||
|
|
||||||
// Set-up CRT stuff
|
// Set-up CRT stuff
|
||||||
srand(0);
|
srand(0);
|
||||||
|
@ -145,3 +141,45 @@ char *getenv(const char *name) {
|
||||||
GetEnvironmentVariable(name, env_string, env_length);
|
GetEnvironmentVariable(name, env_string, env_length);
|
||||||
return env_string;
|
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 <stdio.h>
|
||||||
|
#include <win.h>
|
||||||
|
#include <stddef.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdbool.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 {
|
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 *stdout;
|
||||||
FILE *stdin;
|
FILE *stdin;
|
||||||
FILE *stderr;
|
FILE *stderr;
|
||||||
|
|
||||||
int system(const char* string) {
|
// Linked list because I'm based and you can't say I'm wrong
|
||||||
int wchars_required = MultiByteToWideChar(65001, 0, string, -1, NULL, 0);
|
static FILE *file_list_last = NULL;
|
||||||
wchar_t* cmd_line = malloc(sizeof(L"cmd.exe ") + (wchars_required * sizeof(wchar_t)));
|
|
||||||
if (cmd_line == NULL) {
|
static inline FILE *new_file(
|
||||||
goto error;
|
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 {
|
||||||
memcpy(cmd_line, L"cmd.exe ", sizeof(L"cmd.exe "));
|
file_list_last = file;
|
||||||
MultiByteToWideChar(65001, 0, string, -1, cmd_line + sizeof("cmd.exe ") - 1, wchars_required);
|
file->prev = NULL;
|
||||||
|
file->next = NULL;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
return file;
|
||||||
// Wait until child process exits.
|
}
|
||||||
WaitForSingleObject(pi.hProcess, INFINITE);
|
|
||||||
|
static inline void dispose_file(FILE *file) {
|
||||||
DWORD exit_code;
|
mtx_t lock = file->lock;
|
||||||
if (!GetExitCodeProcess(pi.hProcess, &exit_code)) {
|
mtx_lock(&lock);
|
||||||
goto error;
|
// Only close the file if it's not a standard handle
|
||||||
}
|
if(file->name) {
|
||||||
|
CloseHandle(file->handle);
|
||||||
// Close process and thread handles.
|
//TODO: free(file->name);
|
||||||
CloseHandle(pi.hProcess);
|
}
|
||||||
CloseHandle(pi.hThread);
|
// TODO: flush streams
|
||||||
free(cmd_line);
|
FILE *prev = file->prev;
|
||||||
return exit_code;
|
FILE *next = file->next;
|
||||||
|
if(prev != NULL) prev->next = next;
|
||||||
error:
|
if(next != NULL) next->prev = prev;
|
||||||
free(cmd_line);
|
if(next == NULL) file_list_last = prev;
|
||||||
return -1;
|
free(file);
|
||||||
|
mtx_unlock(&lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _setup_io() {
|
||||||
|
HANDLE hstdout = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||||
|
HANDLE hstderr = GetStdHandle(STD_ERROR_HANDLE);
|
||||||
|
HANDLE hstdin = GetStdHandle(STD_INPUT_HANDLE);
|
||||||
|
|
||||||
|
char *out_buf = calloc(BUFSIZ, sizeof(char));
|
||||||
|
char *err_buf = out_buf;
|
||||||
|
if(hstdout != hstderr) {
|
||||||
|
err_buf = calloc(BUFSIZ, sizeof(char));
|
||||||
|
}
|
||||||
|
|
||||||
|
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:
|
locale.h:
|
||||||
Make other locales actually work
|
Make other locales actually work
|
||||||
|
|
||||||
|
@ -36,6 +40,7 @@ stdlib.h:
|
||||||
|
|
||||||
threads.h:
|
threads.h:
|
||||||
Make _Thread_local work on windows
|
Make _Thread_local work on windows
|
||||||
|
Verify the mtx_recursive goes ok. Also change win_stdio.c accordingly.
|
||||||
TODO: add todo items
|
TODO: add todo items
|
||||||
|
|
||||||
tgmath.h:
|
tgmath.h:
|
||||||
|
|
Loading…
Reference in New Issue