rewrite init to restart failed processes, add file renaming, directory creation, directory renaming, directory removal, add process killing, unify shells, readme changes.
This commit is contained in:
1 parent
f80e66ecde
commit
ddb074f0e0
16 files changed
+476
-641
No files matched your search
+63
-258
@@ -4,85 +4,42 @@
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
// !Made-up! clear console api.
|
||||
BOOL ClearConsoleScreenBuffer(HANDLE hConsole);
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Global handles
|
||||
// ---------------------------------------------------------------------------
|
||||
#define MAX_CMD 256
|
||||
static HANDLE hIn = INVALID_HANDLE_VALUE;
|
||||
static HANDLE hOut = INVALID_HANDLE_VALUE;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Output helpers
|
||||
// ---------------------------------------------------------------------------
|
||||
// External/Custom API
|
||||
BOOL ClearConsoleScreenBuffer(HANDLE hConsole);
|
||||
|
||||
// --- 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);
|
||||
}
|
||||
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;
|
||||
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);
|
||||
while (i > 0) { char c[2] = { buf[--i], '\0' }; print(c); }
|
||||
}
|
||||
|
||||
static void printInt(int32_t n) {
|
||||
char buf[12];
|
||||
int i = 0;
|
||||
uint32_t val = (n < 0) ? (print("-"), (uint32_t)-(n + 1) + 1) : (uint32_t)n;
|
||||
|
||||
if (val == 0) { print("0"); return; }
|
||||
|
||||
while (val > 0) {
|
||||
buf[i++] = (char)('0' + (val % 10));
|
||||
val /= 10;
|
||||
}
|
||||
|
||||
while (i > 0) {
|
||||
char c[2] = { buf[--i], '\0' };
|
||||
print(c); // Assumes print() handles strings
|
||||
}
|
||||
if (n < 0) { print("-"); n = -n; }
|
||||
printUInt((uint32_t)n);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Line editor
|
||||
// ---------------------------------------------------------------------------
|
||||
#define MAX_CMD 256
|
||||
|
||||
// --- Line Editor ---
|
||||
static void readLine(char* buf, int len) {
|
||||
int pos = 0;
|
||||
while (true) {
|
||||
char c;
|
||||
DWORD nRead;
|
||||
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 (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' };
|
||||
@@ -100,253 +57,101 @@ static char* trim(char* s) {
|
||||
return s;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Built-in commands
|
||||
// ---------------------------------------------------------------------------
|
||||
// --- Built-in Commands ---
|
||||
static void cmd_help() {
|
||||
print("Available commands:\n"
|
||||
" help - Show this list\n"
|
||||
" dir - List files in current directory\n"
|
||||
" cd <path> - Change directory\n"
|
||||
" type <file> - Display file contents\n"
|
||||
" del <file> - Delete a file\n"
|
||||
" write <file> <tx> - Create a file with text\n"
|
||||
" exit - Close the shell\n");
|
||||
" help - Show this list\n"
|
||||
" dir [path] - List directory contents\n"
|
||||
" cd <path> - Change directory\n"
|
||||
" type <file> - Display file contents\n"
|
||||
" del <file> - Delete a file\n"
|
||||
" write <file> <tx> - Create a file with text\n"
|
||||
" clear - Clear the screen\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)
|
||||
char filename[MAX_PATH]; int i = 0;
|
||||
while (args[i] != ' ' && args[i] != '\0' && i < MAX_PATH - 1) {
|
||||
filename[i] = args[i];
|
||||
i++;
|
||||
filename[i] = args[i]; i++;
|
||||
}
|
||||
filename[i] = '\0';
|
||||
|
||||
if (args[i] == '\0' || args[i+1] == '\0') {
|
||||
print("write: usage: write <filename> <text>\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;
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
WriteFile(hFile, args + i + 1, (DWORD)strlen(args + i + 1), &written, 0);
|
||||
CloseHandle(hFile);
|
||||
print("File written successfully.\n");
|
||||
}
|
||||
|
||||
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 path_len = 0;
|
||||
while (path[path_len] != '\0' && path_len < MAX_PATH) {
|
||||
path_len++;
|
||||
}
|
||||
|
||||
// Ensure we have room for the path + "\*" + null terminator
|
||||
if (path_len + 3 > MAX_PATH) {
|
||||
print("dir: path too long\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Manual concatenation
|
||||
memcpy(search_path, path, path_len);
|
||||
|
||||
// Append the wildcard pattern
|
||||
search_path[path_len] = '\\';
|
||||
search_path[path_len + 1] = '*';
|
||||
search_path[path_len + 2] = '\0';
|
||||
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) {
|
||||
if (GetLastError() == ERROR_FILE_NOT_FOUND) {
|
||||
return;
|
||||
}
|
||||
print("dir: failed to read directory\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (hFind == INVALID_HANDLE_VALUE) { print("dir: failed to read directory\n"); return; }
|
||||
do {
|
||||
// Skip the "." and ".." entries to keep output clean
|
||||
if (path_len > 0 && fd.cFileName[0] == '.') {
|
||||
if (fd.cFileName[1] == '\0' || (fd.cFileName[1] == '.' && fd.cFileName[2] == '\0')) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
print("<DIR> ");
|
||||
} else {
|
||||
print(" ");
|
||||
}
|
||||
print(fd.cFileName);
|
||||
print("\n");
|
||||
if (fd.cFileName[0] == '.') continue; // Skip . and ..
|
||||
print(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ? "<DIR> " : " ");
|
||||
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;
|
||||
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);
|
||||
buffer[bytesRead] = '\0'; print(buffer);
|
||||
}
|
||||
|
||||
CloseHandle(hFile);
|
||||
print("\n");
|
||||
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;
|
||||
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) { SetCurrentDirectoryA(cmd + 3); 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; }
|
||||
|
||||
// --- Built-in commands ---
|
||||
if (strcmp(cmd, "exit") == 0) {
|
||||
return 1;
|
||||
STARTUPINFOA si = { sizeof(si) }; PROCESS_INFORMATION pi;
|
||||
char cmdBuf[MAX_CMD]; strncpy(cmdBuf, cmd, MAX_CMD-1);
|
||||
if (CreateProcessA(NULL, cmdBuf, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) {
|
||||
WaitForSingleObject(pi.hProcess, INFINITE);
|
||||
CloseHandle(pi.hProcess); CloseHandle(pi.hThread);
|
||||
} else {
|
||||
print("shell: launch failed\n");
|
||||
}
|
||||
|
||||
if (strcmp(cmd, "help") == 0) {
|
||||
cmd_help();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strcmp(cmd, "crash") == 0) {
|
||||
*(int*)0 = 42;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strcmp(cmd, "clear") == 0) {
|
||||
ClearConsoleScreenBuffer(hOut);
|
||||
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) {
|
||||
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);
|
||||
|
||||
FlushConsoleInputBuffer(hOut);
|
||||
|
||||
DWORD exitCode = 0;
|
||||
GetExitCodeProcess(pi.hProcess, &exitCode);
|
||||
CloseHandle(pi.hProcess);
|
||||
CloseHandle(pi.hThread);
|
||||
|
||||
if (exitCode != 0) {
|
||||
print("shell: '");
|
||||
print(cmd);
|
||||
print("' exited with code ");
|
||||
printInt(exitCode);
|
||||
print("\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Entry point
|
||||
// ---------------------------------------------------------------------------
|
||||
int main(const char* cmdline) {
|
||||
int main() {
|
||||
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;
|
||||
if (runCommand(trim(lineBuf))) break;
|
||||
}
|
||||
|
||||
print("shell: goodbye\n");
|
||||
ExitProcess(0);
|
||||
}
|
||||
Reference in new issue
Block a user