feat: add cwd tracking to kernel, remove shell hack, update system utilities to use getcwd, fix tcc libc stub, fix nonexistent directory issue
This commit is contained in:
+26
-148
@@ -6,6 +6,21 @@
|
||||
|
||||
#include "shell.h"
|
||||
|
||||
static void print_ls_entry(const char* entry) {
|
||||
int len = slen(entry);
|
||||
bool hadTrailingSlash = len > 0 && entry[len - 1] == '/';
|
||||
|
||||
while (len > 0 && entry[len - 1] == '/') len--;
|
||||
|
||||
int base = 0;
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (entry[i] == '/') base = i + 1;
|
||||
}
|
||||
|
||||
for (int i = base; i < len; i++) montauk::putchar(entry[i]);
|
||||
if (hadTrailingSlash) montauk::putchar('/');
|
||||
}
|
||||
|
||||
// ---- help ----
|
||||
|
||||
void cmd_help() {
|
||||
@@ -67,28 +82,9 @@ void cmd_help() {
|
||||
void cmd_ls(const char* arg) {
|
||||
arg = skip_spaces(arg);
|
||||
|
||||
char dir[128];
|
||||
int drive = current_drive;
|
||||
if (*arg) {
|
||||
if (has_drive_prefix(arg)) {
|
||||
drive = parse_drive_prefix(arg);
|
||||
int plen = drive_prefix_len(arg);
|
||||
scopy(dir, arg + plen + 1, sizeof(dir));
|
||||
} else if (arg[0] == '/') {
|
||||
scopy(dir, arg + 1, sizeof(dir));
|
||||
} else if (cwd[0]) {
|
||||
scopy(dir, cwd, sizeof(dir));
|
||||
scat(dir, "/", sizeof(dir));
|
||||
scat(dir, arg, sizeof(dir));
|
||||
} else {
|
||||
scopy(dir, arg, sizeof(dir));
|
||||
}
|
||||
} else {
|
||||
scopy(dir, cwd, sizeof(dir));
|
||||
}
|
||||
|
||||
char path[128];
|
||||
build_drive_path(drive, dir, path, sizeof(path));
|
||||
if (*arg) scopy(path, arg, sizeof(path));
|
||||
else scopy(path, ".", sizeof(path));
|
||||
|
||||
const char* entries[64];
|
||||
int count = montauk::readdir(path, entries, 64);
|
||||
@@ -97,16 +93,9 @@ void cmd_ls(const char* arg) {
|
||||
return;
|
||||
}
|
||||
|
||||
int prefixLen = 0;
|
||||
if (dir[0]) prefixLen = slen(dir) + 1;
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
montauk::print(" ");
|
||||
if (prefixLen > 0 && starts_with(entries[i], dir)) {
|
||||
montauk::print(entries[i] + prefixLen);
|
||||
} else {
|
||||
montauk::print(entries[i]);
|
||||
}
|
||||
print_ls_entry(entries[i]);
|
||||
montauk::putchar('\n');
|
||||
}
|
||||
}
|
||||
@@ -116,141 +105,30 @@ void cmd_ls(const char* arg) {
|
||||
bool switch_drive(int drive) {
|
||||
char path[8];
|
||||
build_drive_path(drive, "", path, sizeof(path));
|
||||
const char* entries[1];
|
||||
if (montauk::readdir(path, entries, 1) < 0) return false;
|
||||
current_drive = drive;
|
||||
cwd[0] = '\0';
|
||||
if (montauk::chdir(path) < 0) return false;
|
||||
sync_cwd();
|
||||
return true;
|
||||
}
|
||||
|
||||
int cmd_cd(const char* arg) {
|
||||
arg = skip_spaces(arg);
|
||||
|
||||
// cd with no argument -> go to home directory (or root if no session)
|
||||
if (*arg == '\0') {
|
||||
if (session_home[0] && has_drive_prefix(session_home)) {
|
||||
int drive = parse_drive_prefix(session_home);
|
||||
int plen = drive_prefix_len(session_home);
|
||||
const char* rel = session_home + plen;
|
||||
if (*rel == '/') rel++;
|
||||
current_drive = drive;
|
||||
if (*rel) scopy(cwd, rel, sizeof(cwd));
|
||||
else cwd[0] = '\0';
|
||||
} else {
|
||||
cwd[0] = '\0';
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// cd / -> go to root
|
||||
if (streq(arg, "/")) {
|
||||
cwd[0] = '\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Strip trailing slashes from argument
|
||||
static char argBuf[128];
|
||||
int aLen = 0;
|
||||
while (arg[aLen] && aLen < 127) { argBuf[aLen] = arg[aLen]; aLen++; }
|
||||
argBuf[aLen] = '\0';
|
||||
while (aLen > 0 && argBuf[aLen - 1] == '/') argBuf[--aLen] = '\0';
|
||||
arg = argBuf;
|
||||
|
||||
if (*arg == '\0') {
|
||||
cwd[0] = '\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
// cd .. -> go up one level
|
||||
if (streq(arg, "..")) {
|
||||
int len = slen(cwd);
|
||||
int last = -1;
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (cwd[i] == '/') last = i;
|
||||
}
|
||||
if (last >= 0) {
|
||||
cwd[last] = '\0';
|
||||
} else {
|
||||
cwd[0] = '\0';
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// cd /path -> absolute path from root
|
||||
if (arg[0] == '/') {
|
||||
arg++;
|
||||
if (*arg == '\0') { cwd[0] = '\0'; return 0; }
|
||||
char path[128];
|
||||
build_dir_path(arg, path, sizeof(path));
|
||||
const char* entries[1];
|
||||
if (montauk::readdir(path, entries, 1) < 0) {
|
||||
montauk::print("cd: no such directory: ");
|
||||
montauk::print(arg);
|
||||
montauk::putchar('\n');
|
||||
return 1;
|
||||
}
|
||||
scopy(cwd, arg, sizeof(cwd));
|
||||
return 0;
|
||||
}
|
||||
|
||||
// cd N:/ or cd N:/path -> switch drive
|
||||
if (has_drive_prefix(arg)) {
|
||||
int drive = parse_drive_prefix(arg);
|
||||
int plen = drive_prefix_len(arg);
|
||||
const char* rel = arg + plen;
|
||||
if (*rel == '/') rel++;
|
||||
|
||||
char rootPath[8];
|
||||
build_drive_path(drive, "", rootPath, sizeof(rootPath));
|
||||
const char* rootEntries[1];
|
||||
if (montauk::readdir(rootPath, rootEntries, 1) < 0) {
|
||||
montauk::print("cd: no such drive: ");
|
||||
montauk::print(arg);
|
||||
montauk::putchar('\n');
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (*rel != '\0') {
|
||||
char path[128];
|
||||
build_drive_path(drive, rel, path, sizeof(path));
|
||||
const char* entries[1];
|
||||
if (montauk::readdir(path, entries, 1) < 0) {
|
||||
montauk::print("cd: no such directory: ");
|
||||
montauk::print(arg);
|
||||
montauk::putchar('\n');
|
||||
return 1;
|
||||
}
|
||||
current_drive = drive;
|
||||
scopy(cwd, rel, sizeof(cwd));
|
||||
} else {
|
||||
current_drive = drive;
|
||||
cwd[0] = '\0';
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Relative path
|
||||
char target[128];
|
||||
if (cwd[0]) {
|
||||
scopy(target, cwd, sizeof(target));
|
||||
scat(target, "/", sizeof(target));
|
||||
scat(target, arg, sizeof(target));
|
||||
if (*arg == '\0') {
|
||||
if (session_home[0]) scopy(target, session_home, sizeof(target));
|
||||
else scopy(target, "/", sizeof(target));
|
||||
} else {
|
||||
scopy(target, arg, sizeof(target));
|
||||
}
|
||||
|
||||
char path[128];
|
||||
build_dir_path(target, path, sizeof(path));
|
||||
const char* entries[1];
|
||||
int count = montauk::readdir(path, entries, 1);
|
||||
if (count < 0) {
|
||||
if (montauk::chdir(target) < 0) {
|
||||
montauk::print("cd: no such directory: ");
|
||||
montauk::print(arg);
|
||||
montauk::print(target);
|
||||
montauk::putchar('\n');
|
||||
return 1;
|
||||
}
|
||||
|
||||
scopy(cwd, target, sizeof(cwd));
|
||||
sync_cwd();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
+13
-65
@@ -36,81 +36,29 @@ static void build_cwd_path(const char* name, char* out, int outMax) {
|
||||
scat(out, name, outMax);
|
||||
}
|
||||
|
||||
// ---- Resolve arguments: expand relative file paths against CWD ----
|
||||
|
||||
static void resolve_args(const char* args, char* out, int outMax) {
|
||||
if (!args || !args[0]) { out[0] = '\0'; return; }
|
||||
|
||||
int o = 0;
|
||||
const char* p = args;
|
||||
|
||||
while (*p && o < outMax - 1) {
|
||||
while (*p == ' ' && o < outMax - 1) { out[o++] = *p++; }
|
||||
if (!*p) break;
|
||||
|
||||
const char* tokStart = p;
|
||||
int tokLen = 0;
|
||||
while (p[tokLen] && p[tokLen] != ' ') tokLen++;
|
||||
|
||||
bool resolve = (cwd[0] || current_drive != 0) && !has_drive_prefix(tokStart) && tokStart[0] != '-';
|
||||
|
||||
if (resolve) {
|
||||
char candidate[256];
|
||||
int r = 0;
|
||||
if (current_drive >= 10) candidate[r++] = '0' + current_drive / 10;
|
||||
candidate[r++] = '0' + current_drive % 10;
|
||||
candidate[r++] = ':'; candidate[r++] = '/';
|
||||
int j = 0;
|
||||
while (cwd[j] && r < 255) candidate[r++] = cwd[j++];
|
||||
if (cwd[0] && r < 255) candidate[r++] = '/';
|
||||
|
||||
// Strip leading "./" from token
|
||||
int skip = 0;
|
||||
if (tokLen >= 2 && tokStart[0] == '.' && tokStart[1] == '/') skip = 2;
|
||||
|
||||
for (int k = skip; k < tokLen && r < 255; k++) candidate[r++] = tokStart[k];
|
||||
candidate[r] = '\0';
|
||||
|
||||
int h = montauk::open(candidate);
|
||||
if (h >= 0) {
|
||||
montauk::close(h);
|
||||
for (int k = 0; k < r && o < outMax - 1; k++) out[o++] = candidate[k];
|
||||
} else {
|
||||
bool looksLikeFile = false;
|
||||
for (int k = 0; k < tokLen; k++) {
|
||||
if (tokStart[k] == '.') { looksLikeFile = true; break; }
|
||||
}
|
||||
if (looksLikeFile) {
|
||||
for (int k = 0; k < r && o < outMax - 1; k++) out[o++] = candidate[k];
|
||||
} else {
|
||||
for (int k = 0; k < tokLen && o < outMax - 1; k++) out[o++] = tokStart[k];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int k = 0; k < tokLen && o < outMax - 1; k++) out[o++] = tokStart[k];
|
||||
}
|
||||
|
||||
p = tokStart + tokLen;
|
||||
}
|
||||
out[o] = '\0';
|
||||
}
|
||||
|
||||
// ---- Search and execute an external command ----
|
||||
|
||||
int exec_external(const char* cmd, const char* args) {
|
||||
char path[256];
|
||||
|
||||
char resolvedArgs[512];
|
||||
resolve_args(args, resolvedArgs, sizeof(resolvedArgs));
|
||||
const char* finalArgs = resolvedArgs[0] ? resolvedArgs : nullptr;
|
||||
const char* finalArgs = (args && args[0]) ? args : nullptr;
|
||||
|
||||
// Strip leading "./" from command name
|
||||
const char* name = cmd;
|
||||
if (name[0] == '.' && name[1] == '/') name += 2;
|
||||
|
||||
// 0. If cmd has a drive prefix (absolute path), try it directly
|
||||
if (has_drive_prefix(cmd)) {
|
||||
// 0. Direct paths are resolved by the kernel against the process CWD.
|
||||
bool hasSlash = false;
|
||||
for (int i = 0; cmd[i]; i++) {
|
||||
if (cmd[i] == '/') {
|
||||
hasSlash = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (has_drive_prefix(cmd) || cmd[0] == '/' || cmd[0] == '.' || hasSlash) {
|
||||
if (try_exec(cmd, finalArgs)) return 0;
|
||||
scopy(path, cmd, sizeof(path));
|
||||
scat(path, ".elf", sizeof(path));
|
||||
if (try_exec(path, finalArgs)) return 0;
|
||||
montauk::print(cmd);
|
||||
montauk::print(": not found\n");
|
||||
return 127;
|
||||
|
||||
@@ -14,6 +14,28 @@ int last_exit = 0;
|
||||
char session_user[32] = "";
|
||||
char session_home[64] = "";
|
||||
|
||||
void sync_cwd() {
|
||||
char abs[128];
|
||||
if (montauk::getcwd(abs, sizeof(abs)) < 0) {
|
||||
current_drive = 0;
|
||||
cwd[0] = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
int drive = parse_drive_prefix(abs);
|
||||
if (drive < 0) {
|
||||
current_drive = 0;
|
||||
cwd[0] = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
current_drive = drive;
|
||||
int plen = drive_prefix_len(abs);
|
||||
const char* rel = abs + plen;
|
||||
if (*rel == '/') rel++;
|
||||
scopy(cwd, rel, sizeof(cwd));
|
||||
}
|
||||
|
||||
// ---- Session info (read once at startup) ----
|
||||
|
||||
void read_session() {
|
||||
@@ -165,6 +187,7 @@ static int process_command(const char* line) {
|
||||
if (streq(cmd, "false")) { return 1; }
|
||||
|
||||
if (streq(cmd, "pwd")) {
|
||||
sync_cwd();
|
||||
char path[128];
|
||||
build_dir_path(cwd, path, sizeof(path));
|
||||
montauk::print(path);
|
||||
@@ -202,6 +225,7 @@ static int process_command(const char* line) {
|
||||
montauk::print(session_home);
|
||||
montauk::putchar('\n');
|
||||
}
|
||||
sync_cwd();
|
||||
char path[128];
|
||||
build_dir_path(cwd, path, sizeof(path));
|
||||
montauk::print("PWD=");
|
||||
@@ -331,6 +355,7 @@ static constexpr uint8_t SC_RIGHT = 0x4D;
|
||||
// ---- Entry point ----
|
||||
|
||||
extern "C" void _start() {
|
||||
sync_cwd();
|
||||
read_session();
|
||||
|
||||
montauk::print("\n");
|
||||
|
||||
@@ -113,6 +113,7 @@ const char* var_user_value(int idx);
|
||||
// ---- Session (main.cpp) ----
|
||||
|
||||
void read_session();
|
||||
void sync_cwd();
|
||||
|
||||
// ---- Builtins (builtins.cpp) ----
|
||||
|
||||
|
||||
@@ -61,6 +61,7 @@ const char* var_get(const char* name) {
|
||||
if (streq(name, "USER")) return session_user[0] ? session_user : nullptr;
|
||||
if (streq(name, "HOME")) return session_home[0] ? session_home : nullptr;
|
||||
if (streq(name, "PWD")) {
|
||||
sync_cwd();
|
||||
build_dir_path(cwd, synth, sizeof(synth));
|
||||
return synth;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user