#include #include #include // --------------------------------------------------------------------------- // Win32 imports // --------------------------------------------------------------------------- _Noreturn void ExitProcess(unsigned int code); void OutputDebugStringA(const char* s); typedef void* HANDLE; typedef unsigned long DWORD; typedef int BOOL; #define INVALID_HANDLE_VALUE ((HANDLE)0) #define INFINITE 0xFFFFFFFFUL #define STD_INPUT_HANDLE ((DWORD)-10) HANDLE GetStdHandle(DWORD nStdHandle); BOOL ReadConsoleA(HANDLE hConsoleInput, void* lpBuffer, DWORD nNumberOfCharsToRead, DWORD* lpNumberOfCharsRead, void* pInputControl); typedef struct { DWORD cb; char* lpReserved; char* lpDesktop; char* lpTitle; DWORD dwX, dwY, dwXSize, dwYSize; DWORD dwXCountChars, dwYCountChars; DWORD dwFillAttribute, dwFlags; unsigned short wShowWindow, cbReserved2; unsigned char* lpReserved2; HANDLE hStdInput, hStdOutput, hStdError; } STARTUPINFOA; typedef struct { HANDLE hProcess; HANDLE hThread; DWORD dwProcessId; DWORD dwThreadId; } PROCESS_INFORMATION; BOOL CreateProcessA(const char* lpApp, char* lpCmdLine, void* lpPA, void* lpTA, BOOL bInherit, DWORD dwFlags, void* lpEnv, const char* lpDir, STARTUPINFOA* lpSI, PROCESS_INFORMATION* lpPI); DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMs); BOOL GetExitCodeProcess(HANDLE hProcess, DWORD* lpExitCode); BOOL CloseHandle(HANDLE hObject); // --------------------------------------------------------------------------- // Output helpers // --------------------------------------------------------------------------- static void print(const char* s) { OutputDebugStringA(s); } static void printUInt(uint32_t n) { char buf[12]; int i = 0; if (n == 0) { print("0"); return; } while (n > 0) { buf[i++] = (char)('0' + n % 10); n /= 10; } char rev[12]; int j = 0; while (i > 0) rev[j++] = buf[--i]; rev[j] = '\0'; print(rev); } // --------------------------------------------------------------------------- // Line editor // Reads one character at a time via ReadConsoleA, echoes it, handles // backspace, returns on Enter. // --------------------------------------------------------------------------- #define MAX_CMD 256 static void readLine(HANDLE hIn, char* buf, int len) { int pos = 0; while (1) { char c; DWORD nRead; ReadConsoleA(hIn, &c, 1, &nRead, 0); if (!nRead) continue; if (c == '\r' || c == '\n') { print("\n"); break; } if ((c == '\b' || c == 127) && pos > 0) { pos--; print("\b \b"); continue; } if (c < 0x20 || c == 127) continue; if (pos < len - 1) { buf[pos++] = c; char echo[2] = { c, '\0' }; print(echo); } } buf[pos] = '\0'; } // --------------------------------------------------------------------------- // Trim leading/trailing spaces in-place; returns pointer into buf. // --------------------------------------------------------------------------- static char* trim(char* s) { while (*s == ' ') s++; int len = (int)strlen(s); while (len > 0 && s[len - 1] == ' ') len--; s[len] = '\0'; return s; } // --------------------------------------------------------------------------- // Run one command. Returns 1 if the shell should exit. // --------------------------------------------------------------------------- static int runCommand(const char* cmd) { if (!cmd || *cmd == '\0') return 0; if (strcmp(cmd, "exit") == 0) return 1; STARTUPINFOA si; PROCESS_INFORMATION pi; unsigned char* p = (unsigned char*)&si; for (size_t i = 0; i < sizeof(si); i++) p[i] = 0; si.cb = (DWORD)sizeof(si); if (!CreateProcessA(cmd, 0, 0, 0, 0, 0, 0, 0, &si, &pi)) { print("shell: could not launch '"); print(cmd); print("'\n"); return 0; } WaitForSingleObject(pi.hProcess, INFINITE); DWORD exitCode = 0; GetExitCodeProcess(pi.hProcess, &exitCode); CloseHandle(pi.hProcess); if (exitCode != 0) { print("shell: '"); print(cmd); print("' exited with code "); printUInt(exitCode); print("\n"); } return 0; } // --------------------------------------------------------------------------- // Entry point // --------------------------------------------------------------------------- int main() { HANDLE hIn = GetStdHandle(STD_INPUT_HANDLE); char lineBuf[MAX_CMD]; print("shell: ready\n"); while (1) { print("> "); readLine(hIn, lineBuf, MAX_CMD); if (runCommand(trim(lineBuf))) break; } print("shell: goodbye\n"); ExitProcess(0); }