Files
nt-lite/code/shell/shell.c
T

178 lines
5.1 KiB
C

#include <stdint.h>
#include <stddef.h>
#include <string.h>
// ---------------------------------------------------------------------------
// 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);
}