let PROMPT_TEXT = ">"; let CURRENT_DRIVE = "A"; let shell_pwd = [""]; const welcome_text = "TSVM Disk Operating System, version " + _TVDOS.VERSION; function get_prompt_text() { return CURRENT_DRIVE + ":\\" + shell_pwd.join("\\") + PROMPT_TEXT; } function greet() { println(welcome_text); println(); } let shell = {}; // example input: echo "the string" > subdir\test.txt shell.parse = function(input) { let tokens = []; let stringBuffer = ""; let mode = "LITERAL"; // LITERAL, QUOTE, ESCAPE, LIMBO let i = 0 while (i < input.length) { const c = input[i]; /*digraph g { LITERAL -> QUOTE [label="\""] LITERAL -> LIMBO [label="space"] LITERAL -> LITERAL [label=else] QUOTE -> LIMBO [label="\""] QUOTE -> ESCAPE [label="\\"] QUOTE -> QUOTE [label=else] ESCAPE -> QUOTE LIMBO -> LITERAL [label="not space"] LIMBO -> QUOTE [label="\""] LIMBO -> LIMBO [label="space"] }*/ if (mode == "LITERAL") { if (c == ' ') { tokens.push(stringBuffer); stringBuffer = ""; mode = "LIMBO"; } else if (c == '"') { tokens.push(stringBuffer); stringBuffer = ""; mode = "QUOTE"; } else { stringBuffer += c; } } else if (mode == "LIMBO") { if (c == '"') { mode = "QUOTE"; } else if (c != ' ') { mode = "LITERAL"; stringBuffer += c; } } else if (mode == "QUOTE") { if (c == '"') { tokens.push(stringBuffer); stringBuffer = ""; mode = "LIMBO"; } else if (c == '\\') { mode = "ESCAPE"; } else { stringBuffer += c; } } else if (mode == "ESCAPE") { } i += 1; } if (stringBuffer.length > 0) { tokens.push(stringBuffer); } return tokens; } if (exec_args !== undefined) return shell; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// println("Starting TVDOS..."); greet(); let cmdHistory = []; // zeroth element is the oldest let cmdHistoryScroll = 0; // 0 for outside-of-buffer, 1 for most recent while (true) { print(get_prompt_text()); let cmdbuf = ""; while (true) { let key = con.getch(); // printable chars if (key >= 32 && key <= 126) { let s = String.fromCharCode(key); cmdbuf += s; print(s); } // backspace else if (key === 8 && cmdbuf.length > 0) { cmdbuf = cmdbuf.substring(0, cmdbuf.length - 1); print(String.fromCharCode(key)); } // enter else if (key === 10 || key === 13) { println(); try { let tokens = shell.parse(cmdbuf); tokens.forEach(function(it) { println(it+"_"); }); } catch (e) { printerrln(e); } finally { if (cmdbuf.trim().length > 0) cmdHistory.push(cmdbuf); cmdHistoryScroll = 0; break; } } // up arrow else if (key === 19 && cmdHistory.length > 0 && cmdHistoryScroll < cmdHistory.length) { cmdHistoryScroll += 1; // back the cursor in order to type new cmd let x = 0; for (x = 0; x < cmdbuf.length; x++) print(String.fromCharCode(8)); cmdbuf = cmdHistory[cmdHistory.length - cmdHistoryScroll]; // re-type the new command print(cmdbuf); } // down arrow else if (key === 20) { if (cmdHistoryScroll > 0) { // back the cursor in order to type new cmd let x = 0; for (x = 0; x < cmdbuf.length; x++) print(String.fromCharCode(8)); cmdbuf = cmdHistory[cmdHistory.length - cmdHistoryScroll]; // re-type the new command print(cmdbuf); cmdHistoryScroll -= 1; } else { // back the cursor in order to type new cmd let x = 0; for (x = 0; x < cmdbuf.length; x++) print(String.fromCharCode(8)); cmdbuf = ""; } } } } return 0;