ciabatta/src/_win/environment.c

302 lines
8.7 KiB
C
Raw Normal View History

2022-06-20 06:28:03 +00:00
// Windows symbols because windows
int _fltused=0;
2022-07-30 05:15:11 +00:00
#define CMDLINE_CMD_MAX 32767
#define CMDLINE_ARGV_MAX (16384+(98298+(int)sizeof(char*))/(int)sizeof(char*))
2022-06-20 06:28:03 +00:00
extern int main(int argc, char** argv);
#pragma comment(lib, "kernel32.lib")
#pragma comment(lib, "DbgHelp.lib")
2022-06-20 06:28:03 +00:00
// Exit routines
2022-06-27 02:04:46 +00:00
#define ATEXIT_FUNC_COUNT 64
#define ATQEXIT_FUNC_COUNT 64
static void (*atexit_funcs [ATEXIT_FUNC_COUNT])(void);
static void (*atqexit_funcs[ATQEXIT_FUNC_COUNT])(void);
2022-06-20 06:28:03 +00:00
static int atexit_func_count;
2022-06-27 02:04:46 +00:00
static int atqexit_func_count;
2022-06-20 06:28:03 +00:00
2022-06-27 02:04:46 +00:00
static char **get_command_args(int *argc_ptr);
2022-06-20 06:28:03 +00:00
void mainCRTStartup() {
// Set-up some platform stuff
_setup_eh();
2022-06-21 13:32:46 +00:00
_setup_heap();
2022-06-20 06:28:03 +00:00
_setup_timer();
2022-06-21 13:32:46 +00:00
_setup_io();
2022-06-20 06:28:03 +00:00
// 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
2022-06-24 01:38:54 +00:00
// and all the file handles to be freed
2022-06-20 06:28:03 +00:00
exit(exit_code);
}
2022-06-27 02:04:46 +00:00
_Noreturn void quick_exit(int status) {
while(atqexit_func_count--) {
atqexit_funcs[atqexit_func_count]();
}
ExitProcess(status);
}
2022-06-24 01:38:54 +00:00
_Noreturn void exit(int status) {
2022-06-27 02:04:46 +00:00
while(atexit_func_count--) {
atexit_funcs[atqexit_func_count]();
2022-06-24 01:38:54 +00:00
}
_close_io();
ExitProcess(status);
}
_Noreturn void _Exit(int status) {
ExitProcess(status);
}
2022-06-20 06:28:03 +00:00
_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;
}
2022-06-27 02:04:46 +00:00
int at_quick_exit(void (*func)(void)) {
if(atqexit_func_count >= ATQEXIT_FUNC_COUNT) {
return 0;
}
atqexit_funcs[atqexit_func_count++] = func;
return 1;
}
2022-06-20 06:28:03 +00:00
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;
}
2022-06-21 13:32:46 +00:00
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;
}
2022-06-27 02:04:46 +00:00
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;
}
2022-07-30 05:15:11 +00:00
static int cmdline_to_argv8(const wchar_t *cmd, char **argv);
2022-06-27 02:04:46 +00:00
static char **get_command_args(int *argc_ptr) {
2022-07-30 05:15:11 +00:00
static char *argv_buffer[CMDLINE_ARGV_MAX];
// That's right, that's where windows hid the command line
TEB *teb = (TEB *)__readgsqword(offsetof(NT_TIB, Self));
PEB *peb = teb->ProcessEnvironmentBlock;
RTL_USER_PROCESS_PARAMETERS *params = peb->ProcessParameters;
UNICODE_STRING command_line_str = params->CommandLine;
wchar_t *cmdline = command_line_str.Buffer;
// Now we can do the actual job
*argc_ptr = cmdline_to_argv8(cmdline, argv_buffer);
return argv_buffer;
}
2022-06-27 02:04:46 +00:00
2022-07-30 05:15:11 +00:00
// https://github.com/skeeto/scratch/blob/master/misc/cmdline.c#L27
static int cmdline_to_argv8(const wchar_t *cmd, char **argv) {
int argc = 1; // worst case: argv[0] is an empty string
int state = 6; // special argv[0] state
int slash = 0;
char *buf = (char *)(argv + 16384); // second half: byte buffer
argv[0] = buf;
while (*cmd) {
int c = *cmd++;
if (c>>10 == 0x36 && *cmd>>10 == 0x37) { // surrogates?
c = 0x10000 + ((c - 0xd800)<<10) + (*cmd++ - 0xdc00);
}
2022-06-27 02:04:46 +00:00
2022-07-30 05:15:11 +00:00
switch (state) {
case 0: switch (c) { // outside token
case 0x09:
case 0x20: continue;
case 0x22: argv[argc++] = buf;
state = 2;
continue;
case 0x5c: argv[argc++] = buf;
slash = 1;
state = 3;
break;
default : argv[argc++] = buf;
state = 1;
} break;
case 1: switch (c) { // inside unquoted token
case 0x09:
case 0x20: *buf++ = 0;
state = 0;
continue;
case 0x22: state = 2;
continue;
case 0x5c: slash = 1;
state = 3;
break;
} break;
case 2: switch (c) { // inside quoted token
case 0x22: state = 5;
continue;
case 0x5c: slash = 1;
state = 4;
break;
} break;
case 3:
case 4: switch (c) { // backslash sequence
case 0x22: buf -= (1 + slash) >> 1;
if (slash & 1) {
state -= 2;
break;
} // fallthrough
default : cmd--;
state -= 2;
continue;
case 0x5c: slash++;
} break;
case 5: switch (c) { // quoted token exit
default : cmd--;
state = 1;
continue;
case 0x22: state = 1;
} break;
case 6: switch (c) { // begin argv[0]
case 0x09:
case 0x20: *buf++ = 0;
state = 0;
continue;
case 0x22: state = 8;
continue;
default : state = 7;
} break;
case 7: switch (c) { // unquoted argv[0]
case 0x09:
case 0x20: *buf++ = 0;
state = 0;
continue;
} break;
case 8: switch (c) { // quoted argv[0]
case 0x22: *buf++ = 0;
state = 0;
continue;
} break;
}
2022-06-27 02:04:46 +00:00
2022-07-30 05:15:11 +00:00
switch (c & 0x1f0880) { // WTF-8/UTF-8 encoding
case 0x00000: *buf++ = 0x00 | ((c >> 0) ); break;
case 0x00080: *buf++ = 0xc0 | ((c >> 6) );
*buf++ = 0x80 | ((c >> 0) & 63); break;
case 0x00800:
case 0x00880: *buf++ = 0xe0 | ((c >> 12) );
*buf++ = 0x80 | ((c >> 6) & 63);
*buf++ = 0x80 | ((c >> 0) & 63); break;
default : *buf++ = 0xf0 | ((c >> 18) );
*buf++ = 0x80 | ((c >> 12) & 63);
*buf++ = 0x80 | ((c >> 6) & 63);
*buf++ = 0x80 | ((c >> 0) & 63);
}
2022-06-27 02:04:46 +00:00
}
2022-07-30 05:15:11 +00:00
*buf = 0;
argv[argc] = 0;
return argc;
2022-06-27 02:04:46 +00:00
}