diff --git a/inc/stdio.h b/inc/stdio.h index b5e6289..9179ed3 100644 --- a/inc/stdio.h +++ b/inc/stdio.h @@ -1,14 +1,10 @@ #pragma once -#include #include +#include 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 BUFSIZ 512 - -#define EOF (-1) - -#define FOPEN_MAX 20 +#define _IONBF 0 +#define _IOFBF 1 +#define _IOLBF 2 +#define BUFSIZ 512 +#define EOF (-1) +#define FOPEN_MAX 1024 #ifdef _os_win #define FILENAME_MAX 260 diff --git a/inc/uchar.h b/inc/uchar.h index daf6373..7e232b6 100644 --- a/inc/uchar.h +++ b/inc/uchar.h @@ -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); diff --git a/inc/wchar.h b/inc/wchar.h index c406b15..40f91e0 100644 --- a/inc/wchar.h +++ b/inc/wchar.h @@ -1,15 +1,18 @@ #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 #ifndef WEOF -#define WEOF 0 + #define WEOF 0 #endif int fwprintf(FILE * restrict stream, const wchar_t * restrict format, ...); diff --git a/src/win/win.h b/src/win/win.h index 77e4616..649b68e 100644 --- a/src/win/win.h +++ b/src/win/win.h @@ -10,3 +10,4 @@ void _setup_timer(void); void _setup_eh(); void _setup_heap(); +void _setup_io(); diff --git a/src/win/win_environment.c b/src/win/win_environment.c index a30072b..ad86a73 100644 --- a/src/win/win_environment.c +++ b/src/win/win_environment.c @@ -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; +} diff --git a/src/win/win_stdio.c b/src/win/win_stdio.c index 63995d4..37498df 100644 --- a/src/win/win_stdio.c +++ b/src/win/win_stdio.c @@ -1,58 +1,147 @@ -#include - -#include #include +#include +#include #include #include +#include +#include + +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; } - - 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; + else { + file_list_last = file; + file->prev = NULL; + file->next = NULL; } - - // 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; + return file; +} + +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); +} + +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); } diff --git a/todo b/todo index 896ca84..bb2e79a 100644 --- a/todo +++ b/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: