// User application entry points for shell_win32. #include #include #include #include #include #define MAX_CMD 256 static HANDLE hIn = INVALID_HANDLE_VALUE; static HANDLE hOut = INVALID_HANDLE_VALUE; // External/Custom API. BOOL ClearConsoleScreenBuffer(HANDLE hConsole); // --- Output Helpers ---. static void print(const char* s) { DWORD written; if (hOut != INVALID_HANDLE_VALUE) WriteConsoleA(hOut, s, (DWORD)strlen(s), &written, 0); else OutputDebugStringA(s); } // Prints u Int. 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; } while (i > 0) { char c[2] = { buf[--i], '\0' }; print(c); } } // Prints int. static void printInt(int32_t n) { if (n < 0) { print("-"); n = -n; } printUInt((uint32_t)n); } // --- Line Editor ---. 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'; } // Implements the trim operation. 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 [path] - List directory contents\n" " cd - Change directory\n" " type - Display file contents\n" " del - Delete a file\n" " write - Create a file with text\n" " clear - Clear the screen\n" " exit - Close the shell\n"); } // Implements the cmd write operation. static void cmd_write(const char* args) { char filename[MAX_PATH]; int i = 0; 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; } 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; WriteFile(hFile, args + i + 1, (DWORD)strlen(args + i + 1), &written, 0); CloseHandle(hFile); print("File written successfully.\n"); } // Implements the cmd dir operation. static void cmd_dir(const char* path) { WIN32_FIND_DATAA fd; char search_path[MAX_PATH]; const char* target = (path && *path != '\0') ? path : "."; size_t len = strlen(target); if (len + 3 > MAX_PATH) { print("dir: path too long\n"); return; } strcpy(search_path, target); strcat(search_path, "\\*"); HANDLE hFind = FindFirstFileA(search_path, &fd); if (hFind == INVALID_HANDLE_VALUE) { print("dir: failed to read directory\n"); return; } do { print(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ? " " : " "); print(fd.cFileName); print("\n"); } while (FindNextFileA(hFind, &fd)); FindClose(hFind); } // Implements the cmd type operation. 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: cannot open file\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"); } // Runs command. static int runCommand(const char* cmd) { if (!cmd || *cmd == '\0') return 0; if (strcmp(cmd, "exit") == 0) return 1; if (strcmp(cmd, "help") == 0) { cmd_help(); return 0; } if (strcmp(cmd, "clear") == 0) { ClearConsoleScreenBuffer(hOut); return 0; } if (strcmp(cmd, "crash") == 0) { *(int*)0 = 42; return 0; } if (strcmp(cmd, "dir") == 0) { cmd_dir("."); return 0; } if (strncmp(cmd, "dir ", 4) == 0) { cmd_dir(cmd + 4); return 0; } if (strncmp(cmd, "cd ", 3) == 0) { if (!SetCurrentDirectoryA(cmd + 3)) print("cd: failed\n"); return 0; } if (strncmp(cmd, "del ", 4) == 0) { DeleteFileA(cmd + 4); 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; } PROCESS_INFORMATION pi; char cmdBuf[MAX_CMD]; strncpy(cmdBuf, cmd, MAX_CMD - 1); cmdBuf[MAX_CMD - 1] = '\0'; if (CreateProcessA(NULL, cmdBuf, NULL, NULL, FALSE, 0, NULL, NULL, NULL, &pi)) { WaitForSingleObject(pi.hProcess, INFINITE); if (pi.hThread && pi.hThread != INVALID_HANDLE_VALUE) CloseHandle(pi.hThread); if (pi.hProcess && pi.hProcess != INVALID_HANDLE_VALUE) CloseHandle(pi.hProcess); FlushConsoleInputBuffer(hIn); } else { print("shell: launch failed\n"); } return 0; } // Runs the requested operation. int main(void) { hIn = GetStdHandle(STD_INPUT_HANDLE); hOut = GetStdHandle(STD_OUTPUT_HANDLE); const char* cmdline = GetCommandLineA(); char lineBuf[MAX_CMD]; print("shell: command line: "); print(cmdline); print("\n"); print("shell: ready\n"); while (true) { print("> "); readLine(lineBuf, MAX_CMD); if (runCommand(trim(lineBuf))) break; } print("shell: goodbye\n"); ExitProcess(0); }