#include #include #include #include // --------------------------------------------------------------------------- // Win32 imports & definitions // --------------------------------------------------------------------------- _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)(intptr_t)-1) #define INFINITE 0xFFFFFFFFUL #define STD_INPUT_HANDLE ((DWORD)-10) #define STD_OUTPUT_HANDLE ((DWORD)-11) #define MAX_PATH 260 // File I/O constants #define GENERIC_READ 0x80000000L #define GENERIC_WRITE 0x40000000L #define OPEN_EXISTING 3 #define CREATE_ALWAYS 2 #define FILE_SHARE_READ 0x00000001 #define FILE_ATTRIBUTE_DIRECTORY 0x00000010 HANDLE GetStdHandle(DWORD nStdHandle); DWORD GetLastError(); BOOL ReadConsoleA(HANDLE hConsoleInput, void* lpBuffer, DWORD nNumberOfCharsToRead, DWORD* lpNumberOfCharsRead, void* pInputControl); BOOL WriteConsoleA(HANDLE hConsoleOutput, const void* lpBuffer, DWORD nNumberOfCharsToWrite, DWORD* lpNumberOfCharsWritten, void* lpReserved); 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; typedef struct _FILETIME { DWORD dwLowDateTime; DWORD dwHighDateTime; } FILETIME; typedef struct _WIN32_FIND_DATAA { DWORD dwFileAttributes; FILETIME ftCreationTime; FILETIME ftLastAccessTime; FILETIME ftLastWriteTime; DWORD nFileSizeHigh; DWORD nFileSizeLow; DWORD dwReserved0; DWORD dwReserved1; char cFileName[MAX_PATH]; char cAlternateFileName[14]; } WIN32_FIND_DATAA; 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); // File operation imports HANDLE FindFirstFileA(const char* lpFileName, WIN32_FIND_DATAA* lpFindFileData); BOOL FindNextFileA(HANDLE hFindFile, WIN32_FIND_DATAA* lpFindFileData); BOOL FindClose(HANDLE hFindFile); BOOL SetCurrentDirectoryA(const char* lpPathName); BOOL DeleteFileA(const char* lpFileName); HANDLE CreateFileA(const char* lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, void* lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile); BOOL ReadFile(HANDLE hFile, void* lpBuffer, DWORD nNumberOfBytesToRead, DWORD* lpNumberOfBytesRead, void* lpOverlapped); BOOL WriteFile(HANDLE hFile, const void* lpBuffer, DWORD nNumberOfBytesToWrite, DWORD* lpNumberOfBytesWritten, void* lpOverlapped); // --------------------------------------------------------------------------- // Global handles // --------------------------------------------------------------------------- static HANDLE hIn = INVALID_HANDLE_VALUE; static HANDLE hOut = INVALID_HANDLE_VALUE; // --------------------------------------------------------------------------- // Output helpers // --------------------------------------------------------------------------- static void print(const char* s) { DWORD written; // Write to the actual console window if (hOut != INVALID_HANDLE_VALUE) { WriteConsoleA(hOut, s, (DWORD)strlen(s), &written, 0); } else { 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 // --------------------------------------------------------------------------- #define MAX_CMD 256 static void readLine(char* buf, int len) { int pos = 0; while (true) { 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'; } 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; } // --------------------------------------------------------------------------- // Built-in commands // --------------------------------------------------------------------------- static void cmd_help() { print("Available commands:\n" " help - Show this list\n" " dir - List files in current directory\n" " cd - Change directory\n" " type - Display file contents\n" " del - Delete a file\n" " write - Create a file with text\n" " exit - Close the shell\n"); } static void cmd_write(const char* args) { char filename[MAX_PATH]; int i = 0; // Parse filename (up to first space) while (args[i] != ' ' && args[i] != '\0' && i < MAX_PATH - 1) { filename[i] = args[i]; i++; } filename[i] = '\0'; if (args[i] == '\0' || args[i+1] == '\0') { print("write: usage: write \n"); return; } const char* text = args + i + 1; // Content starts after the space HANDLE hFile = CreateFileA(filename, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0); if (hFile == INVALID_HANDLE_VALUE) { print("write: could not create file\n"); return; } DWORD written; if (!WriteFile(hFile, text, (DWORD)strlen(text), &written, 0)) { print("write: error writing to file\n"); } else { print("File written successfully.\n"); } CloseHandle(hFile); } static void cmd_dir() { WIN32_FIND_DATAA fd; HANDLE hFind = FindFirstFileA("*", &fd); if (hFind == INVALID_HANDLE_VALUE) { print("dir: failed to read directory\n"); return; } do { if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { print(" "); } else { print(" "); } print(fd.cFileName); print("\n"); } while (FindNextFileA(hFind, &fd)); FindClose(hFind); } static void cmd_type(const char* filename) { HANDLE hFile = CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0); if (hFile == INVALID_HANDLE_VALUE) { print("type: could not open '"); print(filename); print("'\n"); return; } char buffer[512]; DWORD bytesRead; while (ReadFile(hFile, buffer, sizeof(buffer) - 1, &bytesRead, 0) && bytesRead > 0) { buffer[bytesRead] = '\0'; print(buffer); } CloseHandle(hFile); print("\n"); } // --------------------------------------------------------------------------- // Run one command. Returns 1 if the shell should exit. // --------------------------------------------------------------------------- static int runCommand(const char* cmd) { if (!cmd || *cmd == '\0') return 0; // --- Built-in commands --- if (strcmp(cmd, "exit") == 0) { return 1; } if (strcmp(cmd, "help") == 0) { cmd_help(); return 0; } if (strcmp(cmd, "dir") == 0) { cmd_dir(); return 0; } if (strncmp(cmd, "cd ", 3) == 0) { const char* path = cmd + 3; if (!SetCurrentDirectoryA(path)) { print("cd: failed to change directory to '"); print(path); print("'\n"); } return 0; } if (strncmp(cmd, "del ", 4) == 0) { const char* file = cmd + 4; if (!DeleteFileA(file)) { print("del: failed to delete '"); print(file); print("'\n"); } return 0; } if (strncmp(cmd, "type ", 5) == 0) { cmd_type(cmd + 5); return 0; } if (strncmp(cmd, "write ", 6) == 0) { cmd_write(cmd + 6); return 0; } // --- External Process Execution --- 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); // CreateProcessA requires a mutable buffer for the command line argument char cmdBuf[MAX_CMD]; strncpy(cmdBuf, cmd, MAX_CMD - 1); cmdBuf[MAX_CMD - 1] = '\0'; if (!CreateProcessA(0, cmdBuf, 0, 0, 0, 0, 0, 0, &si, &pi)) { print("shell: could not launch '"); print(cmd); print("', error code: "); printUInt(GetLastError()); print("\n"); return 0; } WaitForSingleObject(pi.hProcess, INFINITE); DWORD exitCode = 0; GetExitCodeProcess(pi.hProcess, &exitCode); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); if (exitCode != 0) { print("shell: '"); print(cmd); print("' exited with code "); printUInt(exitCode); print("\n"); } return 0; } // --------------------------------------------------------------------------- // Entry point // --------------------------------------------------------------------------- int main(const char* cmdline) { hIn = GetStdHandle(STD_INPUT_HANDLE); hOut = GetStdHandle(STD_OUTPUT_HANDLE); char lineBuf[MAX_CMD]; print("shell: ready\n"); print(cmdline); print("\n"); while (true) { print("> "); readLine(lineBuf, MAX_CMD); if (runCommand(trim(lineBuf))) break; } print("shell: goodbye\n"); ExitProcess(0); }