mirror of
https://codeberg.org/TicklishHoneyBee/CLIte.git
synced 2026-03-11 09:04:37 +00:00
311 lines
6.4 KiB
JavaScript
311 lines
6.4 KiB
JavaScript
clite.commands.data = function() {
|
|
// insert commands below this line
|
|
|
|
clite.commands.load('sh',function(args,env,io) {
|
|
var stdio = io.include('stdio');
|
|
var stdlib = io.include('stdlib');
|
|
var term = io.include('term');
|
|
var active_pid = 0;
|
|
var prompt = '$ ';
|
|
var macro = {
|
|
clear:function(args,io) {
|
|
term.clear();
|
|
},
|
|
cd:function(args,io) {
|
|
var dir = env.HOME;
|
|
if (args.length > 1) {
|
|
dir = stdlib.resolvePath(args[1]);
|
|
}
|
|
var fd = stdio.open(dir,false);
|
|
if (!fd) {
|
|
stdio.write(io.stderr,'invalid directory: '+dir);
|
|
return;
|
|
}
|
|
if (!fd.node.data.isdir) {
|
|
stdio.write(io.stderr,'invalid directory: '+dir);
|
|
return;
|
|
}
|
|
stdio.close(fd);
|
|
env.PWD = dir;
|
|
},
|
|
pwd:function(args,io) {
|
|
stdio.write(io.stdout,env.PWD);
|
|
},
|
|
echo:function(args,io) {
|
|
args.shift();
|
|
var txt = args.join(' ');
|
|
stdio.write(io.stdout,txt);
|
|
},
|
|
which:function(args,io) {
|
|
if (args.length <2)
|
|
return;
|
|
if (typeof macro[args[1]] != 'undefined') {
|
|
return;
|
|
}else{
|
|
var path = resolvePATH(args[1]);
|
|
if (!path)
|
|
return;
|
|
stdio.write(io.stdout,args[1]+' is '+path);
|
|
}
|
|
},
|
|
type:function(args,io) {
|
|
if (args.length <2)
|
|
return;
|
|
if (typeof macro[args[1]] != 'undefined') {
|
|
stdio.write(io.stdout,args[1]+' is a shell builtin');
|
|
}else{
|
|
var path = resolvePATH(args[1]);
|
|
if (!path)
|
|
return;
|
|
stdio.write(io.stdout,args[1]+' is '+path);
|
|
}
|
|
},
|
|
whoami:function(args,io) {
|
|
stdio.write(io.stdout,env.USER);
|
|
},
|
|
alias:function(args,io) {
|
|
stdio.write(io.stdout,'unimplemented');
|
|
},
|
|
export:function(args,io) {
|
|
if (args.length == 1) {
|
|
Object.keys(env).forEach(function(key) {
|
|
stdio.write(io.stdout,key+'='+env[key]);
|
|
});
|
|
return;
|
|
}
|
|
var parts = args[1].split('=');
|
|
if (parts.length != 2)
|
|
return;
|
|
env[parts[0]] = parts[1];
|
|
}
|
|
};
|
|
|
|
function active_exit(pid,v) {
|
|
if (pid != active_pid)
|
|
return;
|
|
inputRead();
|
|
}
|
|
|
|
function resolvePATH(txt) {
|
|
if (typeof env.PATH === 'undefined')
|
|
env.PATH = '/bin';
|
|
var paths = env.PATH.split(':');
|
|
var path = null;
|
|
paths.forEach(function(p) {
|
|
if (path)
|
|
return;
|
|
var rp = stdlib.resolvePath(txt,p);
|
|
var fd = stdio.open(rp,false);
|
|
if (fd) {
|
|
stdio.close(fd);
|
|
path = rp;
|
|
}
|
|
});
|
|
return path;
|
|
}
|
|
|
|
function preprocess(txt) {
|
|
var parts = txt.split('$');
|
|
var pptxt = '';
|
|
if (parts.length == 1)
|
|
return txt;
|
|
parts.forEach(function(p,i) {
|
|
if (i > 0) {
|
|
var b = p;
|
|
var e = '';
|
|
if (b[0] == '{') {
|
|
var pi = b.indexOf('}');
|
|
e = b.substring(pi+1);
|
|
b = b.substring(1,pi);
|
|
}else{
|
|
var pi = b.indexOf(' ');
|
|
if (pi > 0) {
|
|
e = b.substring(pi);
|
|
b = b.substring(0,pi);
|
|
}
|
|
}
|
|
if (typeof env[b] === 'string') {
|
|
b = env[b];
|
|
}else{
|
|
b = '';
|
|
}
|
|
pptxt += b+e;
|
|
return;
|
|
}
|
|
pptxt += p;
|
|
});
|
|
txt = pptxt;
|
|
parts = txt.split('`');
|
|
pptxt = '';
|
|
if (parts.length == 1)
|
|
return txt;
|
|
parts.forEach(function(p,i) {
|
|
if (i > 0) {
|
|
var b = p;
|
|
var e = '';
|
|
var pi = b.indexOf('`');
|
|
if (pi > 0) {
|
|
e = b.substring(pi);
|
|
b = b.substring(0,pi);
|
|
}
|
|
// TODO: replace b with the output of the command in b (command substitution)
|
|
pptxt = b+e;
|
|
return;
|
|
}
|
|
pptxt += p;
|
|
});
|
|
return pptxt;
|
|
}
|
|
|
|
function parseScript(fd) {
|
|
var l;
|
|
while ((l = stdio.readLine(fd)) != null) {
|
|
if (l[0] == '#')
|
|
continue;
|
|
run(l,false);
|
|
}
|
|
}
|
|
|
|
function run(txt,interactive) {
|
|
if (txt.length < 1) {
|
|
if (interactive) {
|
|
stdio.write(io.stdout,prompt);
|
|
inputRead();
|
|
}
|
|
return;
|
|
}
|
|
//clite.shell.history.add(txt);
|
|
//clite.shell.history.resetCurrent();
|
|
if (interactive)
|
|
stdio.write(io.stdout,prompt+txt);
|
|
// clear the tty prompt
|
|
term.ttyctrl('prompt','');
|
|
// split command line into arguments
|
|
var args = stdlib.strToArgs(txt);
|
|
args.forEach(function(val,i) {
|
|
args[i] = preprocess(val);
|
|
});
|
|
// prepare io (stdin,stdout,stderr)
|
|
// TODO: check for io redirects and piping, then setup stdio accordingly
|
|
var fio = {
|
|
stdin:io.stdin,
|
|
stdout:io.stdout,
|
|
stderr:io.stderr,
|
|
exit:active_exit, // filled in by fork()
|
|
include:null, // filled in by fork()
|
|
};
|
|
// check for a macro
|
|
// then either run the macro or expand the program to be executed via PATH
|
|
if (typeof macro[args[0]] != 'undefined') {
|
|
var r = macro[args[0]](args,fio);
|
|
if (interactive)
|
|
inputRead();
|
|
return;
|
|
}
|
|
|
|
var path = resolvePATH(args[0]);
|
|
if (!path) {
|
|
stdio.write(io.stderr,'Shell: unknown command: '+args[0]);
|
|
if (interactive)
|
|
inputRead();
|
|
return;
|
|
}
|
|
|
|
function execFunc(env,io) {
|
|
var r = stdlib.exec(path,args,env,io);
|
|
if (r > 0)
|
|
return;
|
|
|
|
if (r == -1) {
|
|
stdlib.write(io.stderr,'Shell: unknown command: '+args[0]);
|
|
io.exit(-1);
|
|
}
|
|
|
|
if (r == -2) {
|
|
stdio.write(io.stderr,'Shell: error in command:'+args[0]);
|
|
io.exit(-1);
|
|
}
|
|
}
|
|
active_pid = stdlib.fork(env,fio,execFunc);
|
|
if (active_pid == 0) {
|
|
stdio.write(io.stderr,'Shell: internal error');
|
|
if (interactive)
|
|
inputRead();
|
|
}
|
|
}
|
|
|
|
function inputControl(key) {
|
|
//try {
|
|
//if (e.key == 'Down' || e.key == 'ArrowDown') {
|
|
//clite.shell.history.down();
|
|
//return false;
|
|
//}
|
|
//if (e.key == 'Up' || e.key == 'ArrowUp') {
|
|
//clite.shell.history.up();
|
|
//return false;
|
|
//}
|
|
//if (e.key == 'Tab') {
|
|
//return false;
|
|
//}
|
|
//var t = clite.term.data.field.value;
|
|
//if (e.key != 'Enter') {
|
|
//clite.shell.history.setCurrent(t);
|
|
//return true;
|
|
//}
|
|
//clite.shell.run(t);
|
|
//return false;
|
|
//} catch(err) {return false;}
|
|
}
|
|
function input(str) {
|
|
if (str[0] == '\1') {
|
|
inputControl(str.substring(1));
|
|
inputRead();
|
|
return;
|
|
}
|
|
|
|
active_pid = 0;
|
|
run(str,true);
|
|
}
|
|
function inputRead() {
|
|
// generate the prompt
|
|
var p = env.PS1;
|
|
if (typeof p === 'undefined')
|
|
p = '${USER}:${PWD}'
|
|
|
|
prompt = preprocess(p);
|
|
if (stdlib.getuid() == 0) {
|
|
prompt += '# ';
|
|
}else{
|
|
prompt += '$ ';
|
|
}
|
|
// set the prompt
|
|
term.ttyctrl('prompt',prompt);
|
|
// then read from stdin
|
|
stdio.read(io.stdin,input);
|
|
}
|
|
|
|
// run a shell script
|
|
if (!stdio.isatty(io.stdin)) {
|
|
parseScript(io.stdin);
|
|
return 0;
|
|
// otherwise we have an interactive shell
|
|
// so run /etc/shrc and ~/.shrc
|
|
}else{
|
|
var fd = stdio.open('/etc/shrc',false);
|
|
if (fd) {
|
|
parseScript(fd);
|
|
stdio.close(fd);
|
|
}
|
|
fd = stdio.open(env.HOME+'/.shrc',false);
|
|
if (fd) {
|
|
parseScript(fd);
|
|
stdio.close(fd);
|
|
}
|
|
}
|
|
|
|
inputRead();
|
|
|
|
return null;
|
|
});
|
|
|
|
}
|