base layer, mostly stolen
This commit is contained in:
+326
@@ -0,0 +1,326 @@
|
||||
#include "string.h"
|
||||
#include "os.h"
|
||||
#include <userenv.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static u64 w32_ticks_per_sec = 1;
|
||||
static u32 w32_thread_context_index;
|
||||
|
||||
void osInit() {
|
||||
LARGE_INTEGER perf_freq = {0};
|
||||
if (QueryPerformanceFrequency(&perf_freq)) {
|
||||
w32_ticks_per_sec = ((u64)perf_freq.HighPart << 32) | perf_freq.LowPart;
|
||||
}
|
||||
timeBeginPeriod(1);
|
||||
|
||||
w32_thread_context_index = TlsAlloc();
|
||||
}
|
||||
|
||||
void* osThreadContextGet() {
|
||||
return TlsGetValue(w32_thread_context_index);
|
||||
}
|
||||
|
||||
void osThreadContextSet(void* ctx) {
|
||||
TlsSetValue(w32_thread_context_index, ctx);
|
||||
}
|
||||
|
||||
// Memory
|
||||
fn void* osMemoryReserve(u64 size) {
|
||||
return VirtualAlloc(0, size, MEM_RESERVE, PAGE_NOACCESS);
|
||||
}
|
||||
|
||||
fn void osMemoryCommit(void* memory, u64 size) {
|
||||
VirtualAlloc(memory, size, MEM_COMMIT, PAGE_READWRITE);
|
||||
}
|
||||
|
||||
fn void osMemoryDecommit(void* memory, u64 size) {
|
||||
VirtualFree(memory, size, MEM_DECOMMIT);
|
||||
}
|
||||
|
||||
fn void osMemoryRelease(void* memory, u64 size) {
|
||||
VirtualFree(memory, 0, MEM_RELEASE);
|
||||
}
|
||||
|
||||
// Time
|
||||
fn u64 osTimeMicrosecondsNow() {
|
||||
u64 result = 0;
|
||||
LARGE_INTEGER perf_counter = {0};
|
||||
if (QueryPerformanceCounter(&perf_counter)) {
|
||||
u64 ticks = ((u64)perf_counter.HighPart << 32) | perf_counter.LowPart;
|
||||
result = ticks * 1000000 / w32_ticks_per_sec;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#define MICROSECONDS_PER_MILLISECOND 1000
|
||||
fn void osSleepMicroseconds(u32 t) {
|
||||
Sleep(t / MICROSECONDS_PER_MILLISECOND);
|
||||
}
|
||||
|
||||
// Files
|
||||
fn bool osFileExists(String filename) {
|
||||
assert(false && "Not Implemented");
|
||||
ScratchMem scratch = scratchGet();
|
||||
StringUTF16Const filename16 = str16FromStr8(&scratch.arena, filename);
|
||||
DWORD ret = GetFileAttributesW((WCHAR*)filename16.string);
|
||||
scratchReturn(&scratch);
|
||||
return (ret != INVALID_FILE_ATTRIBUTES && !(ret & FILE_ATTRIBUTE_DIRECTORY));
|
||||
}
|
||||
|
||||
fn String osFileRead(Arena* arena, ptr filepath) {
|
||||
assert(false && "Not Implemented");
|
||||
String result = {0};
|
||||
return result;
|
||||
}
|
||||
|
||||
fn bool osFileCreate(String filename) {
|
||||
assert(false && "Not Implemented");
|
||||
return false;
|
||||
}
|
||||
|
||||
fn bool osFileCreateWrite(String filename, String data) {
|
||||
assert(false && "Not Implemented");
|
||||
bool result = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
fn bool osFileWrite(String filename, String data) {
|
||||
assert(false && "Not Implemented");
|
||||
bool result = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// Misc
|
||||
fn void osDebugPrint(bool debug_mode, const char * format, ... ) {
|
||||
if (debug_mode) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
vprintf(format, args);
|
||||
va_end(args);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// TUI
|
||||
TermIOs osStartTUI(bool blocking) {
|
||||
TermIOs old_settings;
|
||||
|
||||
// Windows implementation
|
||||
HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
|
||||
HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
|
||||
// Save old console modes
|
||||
GetConsoleMode(hStdin, &old_settings.input_mode);
|
||||
GetConsoleMode(hStdout, &old_settings.output_mode);
|
||||
|
||||
// Set up alternate screen buffer
|
||||
printf("\033[?1049h");
|
||||
fflush(stdout);
|
||||
|
||||
// Disable line input and echo (equivalent to ~ICANON and ~ECHO)
|
||||
DWORD new_input_mode = old_settings.input_mode;
|
||||
new_input_mode &= ~(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT);
|
||||
|
||||
// Enable virtual terminal processing for ANSI escape sequences
|
||||
DWORD new_output_mode = old_settings.output_mode;
|
||||
new_output_mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
|
||||
|
||||
SetConsoleMode(hStdin, new_input_mode);
|
||||
SetConsoleMode(hStdout, new_output_mode);
|
||||
|
||||
SetConsoleOutputCP(CP_UTF8);
|
||||
|
||||
// Note: Windows console is inherently non-blocking when using
|
||||
// ENABLE_LINE_INPUT disabled. You can check for input with:
|
||||
// DWORD events;
|
||||
// GetNumberOfConsoleInputEvents(hStdin, &events);
|
||||
// Or use PeekConsoleInput() before ReadConsoleInput()
|
||||
|
||||
return old_settings;
|
||||
}
|
||||
|
||||
fn void osEndTUI(TermIOs old_terminal_attributes) {
|
||||
HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
|
||||
HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
|
||||
// Restore console modes
|
||||
SetConsoleMode(hStdin, old_terminal_attributes.input_mode);
|
||||
SetConsoleMode(hStdout, old_terminal_attributes.output_mode);
|
||||
|
||||
// cleanup terminal TUI incantations
|
||||
printf("\033[?1049l");
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
fn Dim2 osGetTerminalDimensions() {
|
||||
Dim2 result = {0};
|
||||
|
||||
HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
||||
|
||||
if (GetConsoleScreenBufferInfo(hStdout, &csbi)) {
|
||||
result.width = csbi.srWindow.Right - csbi.srWindow.Left + 1;
|
||||
result.height = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
|
||||
} else {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void osBlitToTerminal(ptr writeable_output_ansi_string, i64 count) {
|
||||
HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
DWORD written;
|
||||
WriteConsole(hStdout, writeable_output_ansi_string, count, &written, NULL);
|
||||
assert(written == count);
|
||||
}
|
||||
|
||||
bool osInitNetwork() {
|
||||
WSADATA wsaData;
|
||||
|
||||
if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
|
||||
WSACleanup();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void osReadConsoleInput(u8* buffer, u32 len) {
|
||||
MemoryZero(buffer, len); // reset the input so it's not contaminated by last keystroke
|
||||
|
||||
if (_kbhit()) {
|
||||
buffer[0] = _getch();
|
||||
bool first_byte_is_special = buffer[0] == 0 || buffer[0] == 224;
|
||||
if (first_byte_is_special && _kbhit()) {
|
||||
u8 windows_key = _getch();
|
||||
switch (windows_key) {
|
||||
case 72: buffer[0] = 27; buffer[1] = 91; buffer[2] = 65; break; // up
|
||||
case 75: buffer[0] = 27; buffer[1] = 91; buffer[2] = 68; break; // left
|
||||
case 77: buffer[0] = 27; buffer[1] = 91; buffer[2] = 67; break; // right
|
||||
case 80: buffer[0] = 27; buffer[1] = 91; buffer[2] = 66; break; // down
|
||||
default: buffer[1] = windows_key;
|
||||
}
|
||||
/*if (_kbhit()) {
|
||||
buffer[2] = _getch();
|
||||
if (_kbhit()) {
|
||||
buffer[3] = _getch();
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
/*
|
||||
HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
|
||||
INPUT_RECORD ir;
|
||||
DWORD read;
|
||||
if (PeekConsoleInput(hStdin, &ir, 1, &read) && read > 0) {
|
||||
ReadConsole(hStdin, buffer, len, &read, NULL);
|
||||
ReadConsoleInput(hStdin, &ir, 1, &read);
|
||||
if (ir.EventType == KEY_EVENT) {
|
||||
buffer[0] = ir.Event.KeyEvent.uChar.AsciiChar;
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
i32 osLanIPAddress() {
|
||||
i32 result = 0;
|
||||
/*
|
||||
IP_ADAPTER_INFO *pAdapterInfo;
|
||||
IP_ADAPTER_INFO *pAdapter = NULL;
|
||||
DWORD dwRetVal = 0;
|
||||
ULONG ulOutBufLen;
|
||||
|
||||
pAdapterInfo = (IP_ADAPTER_INFO *)malloc(sizeof(IP_ADAPTER_INFO));
|
||||
ulOutBufLen = sizeof(IP_ADAPTER_INFO);
|
||||
|
||||
// Make an initial call to GetAdaptersInfo to get the necessary size
|
||||
if (GetAdaptersInfo(pAdapterInfo, &ulOutBufLen) == ERROR_BUFFER_OVERFLOW) {
|
||||
free(pAdapterInfo);
|
||||
pAdapterInfo = (IP_ADAPTER_INFO *)malloc(ulOutBufLen);
|
||||
}
|
||||
|
||||
if ((dwRetVal = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen)) == NO_ERROR) {
|
||||
pAdapter = pAdapterInfo;
|
||||
printf("LAN Addresses:\n");
|
||||
|
||||
// TODO: test this on windows
|
||||
while (pAdapter) {
|
||||
printf("Interface: %s\n", pAdapter->AdapterName);
|
||||
printf("Description: %s\n", pAdapter->Description);
|
||||
printf("IP Address: %s\n", pAdapter->IpAddressList.IpAddress.String);
|
||||
printf("IP Address: %d\n", pAdapter->Address[0] << 24 | pAdapter->Address[1] << 16 | pAdapter->Address[2] << 8 | pAdapter->Address[3]);
|
||||
printf("\n");
|
||||
pAdapter = pAdapter->Next;
|
||||
}
|
||||
} else {
|
||||
printf("GetAdaptersInfo failed: %ld\n", dwRetVal);
|
||||
}
|
||||
|
||||
if (pAdapterInfo) {
|
||||
free(pAdapterInfo);
|
||||
}
|
||||
*/
|
||||
WSADATA wsa;
|
||||
char hostname[256];
|
||||
struct addrinfo hints, *final = NULL, *ptr = NULL;
|
||||
struct sockaddr_in *sockaddr_ipv4;
|
||||
|
||||
// Initialize Winsock
|
||||
if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Get hostname
|
||||
if (gethostname(hostname, sizeof(hostname)) == SOCKET_ERROR) {
|
||||
WSACleanup();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Set up hints for getaddrinfo
|
||||
ZeroMemory(&hints, sizeof(hints));
|
||||
hints.ai_family = AF_INET; // IPv4
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_protocol = IPPROTO_TCP;
|
||||
|
||||
// Get address info
|
||||
if (getaddrinfo(hostname, NULL, &hints, &final) != 0) {
|
||||
WSACleanup();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Loop through results to find a non-loopback address
|
||||
for (ptr = final; ptr != NULL; ptr = ptr->ai_next) {
|
||||
sockaddr_ipv4 = (struct sockaddr_in *)ptr->ai_addr;
|
||||
unsigned long addr = ntohl(sockaddr_ipv4->sin_addr.s_addr);
|
||||
|
||||
// Skip loopback addresses (127.x.x.x)
|
||||
if ((addr >> 24) != 127) {
|
||||
result = sockaddr_ipv4->sin_addr.s_addr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
freeaddrinfo(final);
|
||||
WSACleanup();
|
||||
|
||||
return ntohl(result);
|
||||
}
|
||||
|
||||
bool osThreadJoin(Thread handle, u64 endt_us) {
|
||||
DWORD sleep_ms = os_w32_sleep_ms_from_endt_us(endt_us);
|
||||
OS_W32_Entity *entity = (OS_W32_Entity *)PtrFromInt(handle.u64[0]);
|
||||
DWORD wait_result = WAIT_OBJECT_0;
|
||||
if(entity != 0)
|
||||
{
|
||||
wait_result = WaitForSingleObject(entity->thread.handle, sleep_ms);
|
||||
CloseHandle(entity->thread.handle);
|
||||
os_w32_entity_release(entity);
|
||||
}
|
||||
return (wait_result == WAIT_OBJECT_0);
|
||||
}
|
||||
Reference in New Issue
Block a user