mirror of
https://github.com/curioustorvald/tsvm.git
synced 2026-06-14 00:14:05 +09:00
command.js to run batch file
This commit is contained in:
270
assets/tvdos/bin/command.js
Normal file
270
assets/tvdos/bin/command.js
Normal file
@@ -0,0 +1,270 @@
|
||||
let PROMPT_TEXT = ">";
|
||||
let CURRENT_DRIVE = "A";
|
||||
let executableExtensions = [".com",".bat",".js", ""]; Object.freeze(executableExtensions);
|
||||
let shell_pwd = [];
|
||||
|
||||
const welcome_text = "TSVM Disk Operating System, version " + _TVDOS.VERSION;
|
||||
|
||||
function print_prompt_text() {
|
||||
print(CURRENT_DRIVE + ":\\" + shell_pwd.join("\\") + PROMPT_TEXT);
|
||||
}
|
||||
|
||||
function greet() {
|
||||
println(welcome_text);
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
shell.coreutils = {
|
||||
cd: function(args) {
|
||||
if (args[1] === undefined) {
|
||||
println(shell_pwd.join("\\"));
|
||||
return
|
||||
}
|
||||
|
||||
shell_pwd = args[1].split("\\");
|
||||
},
|
||||
cls: function(args) {
|
||||
con.clear();
|
||||
},
|
||||
exit: function(args) {
|
||||
cmdExit = true;
|
||||
},
|
||||
ver: function(args) {
|
||||
println(welcome_text);
|
||||
},
|
||||
echo: function(args) {
|
||||
if (args[1] !== undefined) {
|
||||
args.forEach(function(it,i) { if (i > 0) print(it+" ") });
|
||||
}
|
||||
println();
|
||||
},
|
||||
rem: function(args) {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
Object.freeze(shell.coreutils);
|
||||
shell.execute = function(line) {
|
||||
if (line.size == 0) return;
|
||||
let tokens = shell.parse(line);
|
||||
let cmd = tokens[0];
|
||||
|
||||
// handle Ctrl-C
|
||||
if (con.hitterminate()) return 1;
|
||||
|
||||
if (shell.coreutils[cmd.toLowerCase()] !== undefined) {
|
||||
let retval = shell.coreutils[cmd.toLowerCase()](tokens);
|
||||
return retval|0; // return value of undefined will cast into 0
|
||||
}
|
||||
else {
|
||||
// search through PATH for execution
|
||||
|
||||
let fileExists = false;
|
||||
let searchDir = (cmd.startsWith("\\")) ? [""] : ["\\"+shell_pwd.join("\\")].concat(_TVDOS.defaults.path);
|
||||
|
||||
searchDir.forEach(function(it) { serial.println("Searchdir: "+it); });
|
||||
|
||||
searchLoop:
|
||||
for (let i = 0; i < searchDir.length; i++) {
|
||||
for (let j = 0; j < executableExtensions.length; j++) {
|
||||
let path = (searchDir[i] + cmd + executableExtensions[j]).substring(1); // without substring, this will always prepend revslash
|
||||
if (filesystem.open(CURRENT_DRIVE, path, "R")) {
|
||||
fileExists = true;
|
||||
break searchLoop;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!fileExists) {
|
||||
printerrln('Bad command or filename: "'+cmd+'"');
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
let prg = filesystem.readAll(CURRENT_DRIVE);
|
||||
let extension = undefined;
|
||||
// get proper extension
|
||||
let dotSepTokens = cmd.split('.');
|
||||
if (dotSepTokens.length > 1) extension = dotSepTokens[dotSepTokens.length - 1].toUpperCase();
|
||||
|
||||
if ("BAT" == extension) {
|
||||
// parse and run as batch file
|
||||
let lines = prg.split('\n').filter(function(it) { return it.length > 0; });
|
||||
lines.forEach(function(line) {
|
||||
shell.execute(line);
|
||||
});
|
||||
}
|
||||
else {
|
||||
return execApp(prg, tokens)|0; // return value of undefined will cast into 0
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
Object.freeze(shell);
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
if (exec_args[1] !== undefined) {
|
||||
// command /c <commands>
|
||||
// ^[0] ^[1] ^[2]
|
||||
if (exec_args[1].toLowerCase() == "/c") {
|
||||
if (exec_args[2] == "") return 0; // no commands were given, just exit successfully
|
||||
return shell.execute(exec_args[2]);
|
||||
}
|
||||
else {
|
||||
printerrln("Invalid switch: "+exec_args[1]);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
con.reset_graphics();
|
||||
println("Starting TVDOS...");
|
||||
greet();
|
||||
|
||||
let cmdHistory = []; // zeroth element is the oldest
|
||||
let cmdHistoryScroll = 0; // 0 for outside-of-buffer, 1 for most recent
|
||||
let cmdExit = false;
|
||||
while (!cmdExit) {
|
||||
print_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 {
|
||||
shell.execute(cmdbuf);
|
||||
}
|
||||
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;
|
||||
106
assets/tvdos/bin/flsh.js
Normal file
106
assets/tvdos/bin/flsh.js
Normal file
@@ -0,0 +1,106 @@
|
||||
let CURRENT_DRIVE = "A";
|
||||
|
||||
let shell_pwd = [""];
|
||||
|
||||
const welcome_text = "TSVM Disk Operating System, version " + _TVDOS.VERSION;
|
||||
|
||||
function print_prompt_text() {
|
||||
// oh-my-zsh-like prompt
|
||||
con.color_pair(239,161);
|
||||
print(" "+CURRENT_DRIVE+":");
|
||||
con.color_pair(161,253);
|
||||
con.addch(16);
|
||||
con.color_pair(0,253);
|
||||
print(" \\"+shell_pwd.join("\\")+" ");
|
||||
con.color_pair(253,255);
|
||||
con.addch(16);
|
||||
con.addch(32);
|
||||
con.color_pair(239,255);
|
||||
}
|
||||
|
||||
function greet() {
|
||||
con.color_pair(0,253);
|
||||
//print(welcome_text + " ".repeat(_fsh.scrwidth - welcome_text.length));
|
||||
print(welcome_text + " ".repeat(80 - welcome_text.length));
|
||||
con.color_pair(239,255);
|
||||
println();
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
con.clear();
|
||||
|
||||
greet();
|
||||
|
||||
let cmdHistory = []; // zeroth element is the oldest
|
||||
let cmdHistoryScroll = 0; // 0 for outside-of-buffer, 1 for most recent
|
||||
while (true) {
|
||||
print_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 {
|
||||
println("You entered: " + cmdbuf);
|
||||
}
|
||||
catch (e) {
|
||||
println(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 = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
131
assets/tvdos/bin/fsh.js
Normal file
131
assets/tvdos/bin/fsh.js
Normal file
@@ -0,0 +1,131 @@
|
||||
graphics.setBackground(3,3,3);
|
||||
graphics.resetPalette();
|
||||
|
||||
function captureUserInput() {
|
||||
sys.poke(-40, 1);
|
||||
}
|
||||
|
||||
function getKeyPushed(keyOrder) {
|
||||
return sys.peek(-41 - keyOrder);
|
||||
}
|
||||
|
||||
var _fsh = {};
|
||||
_fsh.titlebarTex = new GL.Texture(2, 14, base64.atob("/u/+/v3+/f39/f39/f39/f39/P39/Pz8/Pv7+w=="));
|
||||
_fsh.scrdim = con.getmaxyx();
|
||||
_fsh.scrwidth = _fsh.scrdim[1];
|
||||
_fsh.scrheight = _fsh.scrdim[0];
|
||||
_fsh.brandName = "f\xb3Sh";
|
||||
_fsh.brandLogoTexSmall = new GL.Texture(24, 14, gzip.decomp(base64.atob(
|
||||
"H4sIAAAAAAAAAPv/Hy/4Qbz458+fIeILQQBIwoSh6qECuMVBukCmIJkDVQ+RQNgLE0MX/w+1lyhxqIUwTLJ/sQMAcIXsbVABAAA="
|
||||
)));
|
||||
_fsh.scrlayout = ["com.fsh.clock","com.fsh.calendar","com.fsh.apps_n_files"];
|
||||
|
||||
_fsh.drawTitlebar = function(titletext) {
|
||||
GL.drawTexPattern(_fsh.titlebarTex, 0, 0, 560, 14);
|
||||
if (titletext === undefined || titletext.length == 0) {
|
||||
con.move(1,1);
|
||||
print(" ".repeat(_fsh.scrwidth));
|
||||
GL.drawTexImageOver(_fsh.brandLogoTexSmall, 268, 0);
|
||||
}
|
||||
else {
|
||||
con.color_pair(240, 255);
|
||||
GL.drawTexPattern(_fsh.titlebarTex, 268, 0, 24, 14);
|
||||
con.move(1, 1 + (_fsh.scrwidth - titletext.length) / 2);
|
||||
print(titletext);
|
||||
}
|
||||
con.color_pair(254, 255);
|
||||
};
|
||||
|
||||
|
||||
_fsh.Widget = function(id, w, h) {
|
||||
this.identifier = id;
|
||||
this.width = w;
|
||||
this.height = h;
|
||||
|
||||
if (!this.identifier) {
|
||||
this.identifier = "";
|
||||
}
|
||||
|
||||
//this.update = function() {};
|
||||
/**
|
||||
* Params charXoff and charYoff are ZERO-BASED!
|
||||
*/
|
||||
this.draw = function(charXoff, charYoff) {};
|
||||
}
|
||||
|
||||
_fsh.widgets = {}
|
||||
_fsh.registerNewWidget = function(widget) {
|
||||
_fsh.widgets[widget.identifier] = widget;
|
||||
}
|
||||
|
||||
var clockWidget = new _fsh.Widget("com.fsh.clock", _fsh.scrwidth - 8, 7);
|
||||
clockWidget.numberSheet = new GL.SpriteSheet(19, 22, new GL.Texture(190, 22, gzip.decomp(base64.atob(
|
||||
"H4sIAAAAAAAAAMWVW3LEMAgE739aHcFJJV5ZMD2I9ToVfcl4GBr80HF8r/FaR1ozMuIyoUu87lEXI0al5qVR5AebSwchSaNE6Nyo1Nw5HXF3SfPT4Bshl"+
|
||||
"EycA8RD96mLlHbuhTgOrfLnUDZspafbSQWk56WEGvQEtWaWwgb8iz7a8AOXhsraO/q9Qw2/GnXovfVN+q2wM/p/oddn2cjF239GX3y11+SWCtc6FTHC1v"+
|
||||
"TVPkDPWWn0w+DDz93UX9v9mF5KIsQ6OdN2KJoB4ui1bXXr0AMp0YfiQo//4XhpK8555dsNehAqVS5uhb5iHn3Kko769J59KmLBe/TSR7hcsd+hr+HnrwR"+
|
||||
"9uvRF9+D3MP14gN7lqx+8OuNT+uqt3NFX3SN9fTbeeHNq+C29pRWzX5+Rcm7SZyjOKJ/2hkSPqul4xN279DrSYvCrNu2NI7ZMp1ouBxK3KBVVnEeAUWbK"+
|
||||
"MUDn5DPsPxmUqHZQjGpy2hergM3EVBAAAA=="
|
||||
))));
|
||||
|
||||
clockWidget.clockColon = new GL.Texture(4, 3, base64.atob("7+/v7+/v7+/v7+/v"));
|
||||
clockWidget.monthNames = ["Spring", "Summer", "Autumn", "Winter"];
|
||||
clockWidget.dayNames = ["Mondag ", "Tysdag ", "Midtveke", "Torsdag ", "Fredag ", "Laurdag ", "Sundag ", "Verddag "];
|
||||
clockWidget.draw = function(charXoff, charYoff) {
|
||||
con.color_pair(254, 255);
|
||||
var xoff = charXoff * 7;
|
||||
var yoff = charYoff * 14 + 3;
|
||||
var timeInMinutes = ((sys.currentTimeInMills() / 60000)|0);
|
||||
var mins = timeInMinutes % 60;
|
||||
var hours = ((timeInMinutes / 60)|0) % 24;
|
||||
var ordinalDay = ((timeInMinutes / (60*24))|0) % 120;
|
||||
var visualDay = (ordinalDay % 30) + 1;
|
||||
var months = ((timeInMinutes / (60*24*30))|0) % 4;
|
||||
var dayName = ordinalDay % 7; // 0 for Mondag
|
||||
if (ordinalDay == 119) dayName = 7; // Verddag
|
||||
var years = ((timeInMinutes / (60*24*30*120))|0) + 125;
|
||||
// draw timepiece
|
||||
GL.drawSprite(clockWidget.numberSheet, (hours / 10)|0, 0, xoff, yoff);
|
||||
GL.drawSprite(clockWidget.numberSheet, hours % 10, 0, xoff + 24, yoff);
|
||||
GL.drawTexImage(clockWidget.clockColon, xoff + 48, yoff + 5);
|
||||
GL.drawTexImage(clockWidget.clockColon, xoff + 48, yoff + 14);
|
||||
GL.drawSprite(clockWidget.numberSheet, (mins / 10)|0, 0, xoff + 57, yoff);
|
||||
GL.drawSprite(clockWidget.numberSheet, mins % 10, 0, xoff + 81, yoff);
|
||||
// print month and date
|
||||
con.move(1 + charYoff, 17 + charXoff);
|
||||
print(clockWidget.monthNames[months]+" "+visualDay);
|
||||
// print year and dayname
|
||||
con.mvaddch(2 + charYoff, 17 + charXoff, 5);
|
||||
con.move(2 + charYoff, 18 + charXoff);
|
||||
print(years+" "+clockWidget.dayNames[dayName]);
|
||||
};
|
||||
|
||||
|
||||
// register widgets
|
||||
_fsh.registerNewWidget(clockWidget);
|
||||
|
||||
// screen init
|
||||
con.color_pair(254, 255);
|
||||
con.clear();
|
||||
con.curs_set(0);
|
||||
_fsh.drawTitlebar();
|
||||
|
||||
|
||||
// TEST
|
||||
con.move(2,1);
|
||||
print("Hit backspace to exit");
|
||||
while (true) {
|
||||
captureUserInput();
|
||||
if (getKeyPushed(0) == 67) break;
|
||||
|
||||
_fsh.widgets["com.fsh.clock"].draw(25, 2);
|
||||
}
|
||||
|
||||
con.move(3,1);
|
||||
con.color_pair(201,255);
|
||||
print("cya!");
|
||||
|
||||
let konsht = 3412341241;
|
||||
println(konsht);
|
||||
|
||||
let pppp = graphics.getCursorYX();
|
||||
println(pppp.toString());
|
||||
Reference in New Issue
Block a user