2023-11-25 10:43:51 +00:00
|
|
|
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');
|
2023-11-27 09:01:52 +00:00
|
|
|
var clite = io.include('clite');
|
2023-12-19 04:36:09 +00:00
|
|
|
|
2023-11-27 11:46:33 +00:00
|
|
|
var has_exited = false;
|
2023-12-20 10:30:06 +00:00
|
|
|
let builtins = ['clear','cd','pwd','echo','which','type','whoami','alias','export','true','false','exit'];
|
|
|
|
|
let builtins_func = [builtin_clear,builtin_cd,builtin_pwd,builtin_echo,builtin_which,builtin_type,builtin_whoami,builtin_alias,builtin_export,builtin_true,builtin_false,builtin_exit];
|
|
|
|
|
let history_data = [];
|
|
|
|
|
let history_current = '';
|
|
|
|
|
let history_index = 0;
|
|
|
|
|
let parser_files = [];
|
|
|
|
|
let parser_callback = null;
|
|
|
|
|
let parser_lines = [];
|
|
|
|
|
let parser_script = null;
|
|
|
|
|
let exec_callback = null;
|
|
|
|
|
let exec_cmds = [];
|
|
|
|
|
let exec_active = null;
|
|
|
|
|
let exec_bufferout = null;
|
|
|
|
|
let exec_bufferin = null;
|
|
|
|
|
let exec_skipto = null;
|
2023-12-21 00:05:14 +00:00
|
|
|
let exec_closout = false;
|
|
|
|
|
let exec_closin = false;
|
|
|
|
|
let exec_closerr = false;
|
2023-12-20 10:30:06 +00:00
|
|
|
let exec_last = 0;
|
|
|
|
|
let exec_io = {};
|
|
|
|
|
let exec_conditionals = [];
|
|
|
|
|
let exec_loops = [];
|
2023-12-19 04:36:09 +00:00
|
|
|
|
2023-12-20 10:30:06 +00:00
|
|
|
function builtin_clear(args,io) {
|
|
|
|
|
term.clear();
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
function builtin_cd(args,io) {
|
|
|
|
|
var dir = env.HOME;
|
|
|
|
|
if (args.length > 1)
|
|
|
|
|
dir = clite.resolvePath(args[1]);
|
|
|
|
|
var fd = stdio.open(dir,stdio.flags.O_SEARCH|stdio.flags.O_DIRECTORY);
|
|
|
|
|
if (!fd) {
|
|
|
|
|
stdio.fprintf(io.stderr,'invalid directory: %s\n',dir);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
stdio.close(fd);
|
|
|
|
|
env.PWD = dir;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
function builtin_pwd(args,io) {
|
|
|
|
|
stdio.fprintf(io.stdout,'%s\n',env.PWD);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
function builtin_echo(args,io) {
|
|
|
|
|
args.shift();
|
|
|
|
|
var txt = args.join(' ')+'\n';
|
|
|
|
|
stdio.write(io.stdout,txt);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
function builtin_which(args,io) {
|
|
|
|
|
if (args.length <2)
|
|
|
|
|
return 1;
|
|
|
|
|
if (builtins.indexOf(args[1]) > -1) {
|
|
|
|
|
return 1;
|
|
|
|
|
}else{
|
|
|
|
|
var path = resolvePATH(args[1]);
|
|
|
|
|
if (!path)
|
2023-12-14 08:59:15 +00:00
|
|
|
return 1;
|
2023-12-20 10:30:06 +00:00
|
|
|
stdio.fprintf(io.stdout,'%s is %s\n',args[1],path);
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
function builtin_type(args,io) {
|
|
|
|
|
if (args.length <2)
|
|
|
|
|
return 1;
|
|
|
|
|
if (builtins.indexOf(args[1]) > -1) {
|
|
|
|
|
stdio.fprintf(io.stdout,'%s is a shell builtin\n',args[1]);
|
|
|
|
|
}else{
|
|
|
|
|
var path = resolvePATH(args[1]);
|
|
|
|
|
if (!path)
|
2023-12-14 08:59:15 +00:00
|
|
|
return 1;
|
2023-12-20 10:30:06 +00:00
|
|
|
stdio.fprintf(io.stdout,'%s is %s\n',args[1],path);
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
function builtin_whoami(args,io) {
|
|
|
|
|
stdio.fprintf(io.stdout,'%s\n',env.USER);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
function builtin_alias(args,io) {
|
|
|
|
|
stdio.fprintf(io.stdout,'unimplemented\n');
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
function builtin_export(args,io) {
|
|
|
|
|
if (args.length == 1) {
|
|
|
|
|
Object.keys(env).forEach(function(key) {
|
|
|
|
|
stdio.fprintf(io.stdout,'%s=%s\n',key,env[key]);
|
|
|
|
|
});
|
2023-12-15 01:54:48 +00:00
|
|
|
return 0;
|
2023-12-20 10:30:06 +00:00
|
|
|
}
|
|
|
|
|
var parts = args[1].split('=');
|
|
|
|
|
if (parts.length != 2)
|
2023-12-14 08:59:15 +00:00
|
|
|
return 0;
|
2023-12-20 10:30:06 +00:00
|
|
|
env[parts[0]] = parts[1];
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
function builtin_true(args,io) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
function builtin_false(args,io) {
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
function builtin_exit(args,io) {
|
|
|
|
|
var ev = 0;
|
|
|
|
|
if (args.length > 1)
|
|
|
|
|
ev = parseInt(args[1]);
|
|
|
|
|
doShellExit(ev);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function history_load() {
|
|
|
|
|
let path = clite.resolvePath('~/.shhistory');
|
|
|
|
|
let fd = stdio.open(path,stdio.flags.O_RDONLY|stdio.flags.O_SYNC);
|
|
|
|
|
if (!fd)
|
|
|
|
|
return;
|
|
|
|
|
var e;
|
|
|
|
|
while ((e = stdio.readLine(fd)) != null) {
|
|
|
|
|
history_add(e);
|
2023-11-25 10:43:51 +00:00
|
|
|
}
|
2023-12-20 10:30:06 +00:00
|
|
|
stdio.close(fd);
|
|
|
|
|
}
|
|
|
|
|
function history_save() {
|
|
|
|
|
let path = clite.resolvePath('~/.shhistory');
|
|
|
|
|
let fd = stdio.open(path,stdio.flags.O_WRONLY|stdio.flags.O_TRUNC|stdio.flags.O_CREAT|stdio.flags.O_SYNC);
|
|
|
|
|
if (!fd)
|
|
|
|
|
return;
|
|
|
|
|
history_data.forEach(function(l) {
|
|
|
|
|
stdio.write(fd,l+'\n');
|
|
|
|
|
});
|
|
|
|
|
stdio.close(fd);
|
|
|
|
|
}
|
|
|
|
|
function history_add(txt) {
|
|
|
|
|
if (txt.length < 1)
|
|
|
|
|
return;
|
|
|
|
|
if (history_data.length > 0 && history_data[history_data.length-1] == txt)
|
|
|
|
|
return;
|
|
|
|
|
history_data.push(txt);
|
|
|
|
|
history_index = history_data.length;
|
|
|
|
|
}
|
|
|
|
|
function history_up() {
|
|
|
|
|
if (history_index < 1)
|
|
|
|
|
return null;
|
|
|
|
|
history_index--;
|
|
|
|
|
return history_getCurrent();
|
|
|
|
|
}
|
|
|
|
|
function history_down() {
|
|
|
|
|
if (history_index >= history_data.length)
|
|
|
|
|
return null;
|
|
|
|
|
history_index++;
|
|
|
|
|
return history_getCurrent();
|
|
|
|
|
}
|
|
|
|
|
function history_setCurrent(txt) {
|
|
|
|
|
history_current = txt;
|
|
|
|
|
}
|
|
|
|
|
function history_getCurrent() {
|
|
|
|
|
if (history_index >= history_data.length)
|
|
|
|
|
return history_current;
|
|
|
|
|
return history_data[history_index];
|
|
|
|
|
}
|
|
|
|
|
function history_resetCurrent() {
|
|
|
|
|
history_current = '';
|
|
|
|
|
history_index = history_data.length;
|
|
|
|
|
}
|
|
|
|
|
function history_clear() {
|
|
|
|
|
history_data = [];
|
|
|
|
|
history_current = '';
|
|
|
|
|
history_index = 0;
|
|
|
|
|
}
|
2023-11-25 10:43:51 +00:00
|
|
|
|
2023-12-20 10:30:06 +00:00
|
|
|
function parser_queue(file) {
|
|
|
|
|
parser_files.push(file);
|
|
|
|
|
}
|
|
|
|
|
function parser_parseFile(f) {
|
|
|
|
|
var fn = clite.resolvePath(f);
|
|
|
|
|
if (fn == null) {
|
|
|
|
|
parser_run();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
var st = stdio.stat(fn);
|
|
|
|
|
if (st == null || st.type != stdio.types.FT_SCRIPT) {
|
|
|
|
|
parser_run();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
var fd = stdio.open(fn,stdio.flags.O_RDONLY,parser_prepFile);
|
|
|
|
|
if (!fd)
|
|
|
|
|
parser_run();
|
|
|
|
|
}
|
|
|
|
|
function parser_prepFile(fd) {
|
|
|
|
|
var data = stdio.readAll(fd);
|
|
|
|
|
if (fd != io.stdin)
|
2023-12-17 04:57:15 +00:00
|
|
|
stdio.close(fd);
|
2023-12-20 10:30:06 +00:00
|
|
|
if (!data) {
|
|
|
|
|
parser_run();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
parser_script = '';
|
|
|
|
|
parser_lines = data.split('\n');
|
|
|
|
|
if (parser_lines.length < 1) {
|
|
|
|
|
parser_run();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
parser_parseLine();
|
|
|
|
|
}
|
|
|
|
|
function parser_parseLine() {
|
|
|
|
|
var l = parser_lines.shift();
|
|
|
|
|
if (l == null) {
|
|
|
|
|
parser_exec();
|
|
|
|
|
return;
|
2023-11-26 09:54:37 +00:00
|
|
|
}
|
2023-12-20 10:30:06 +00:00
|
|
|
if (l[0] != '#')
|
|
|
|
|
parser_script += l+'; ';
|
|
|
|
|
parser_parseLine();
|
|
|
|
|
}
|
|
|
|
|
function parser_exec() {
|
|
|
|
|
exec_setCommand(parser_script);
|
|
|
|
|
exec_run(parser_run);
|
|
|
|
|
}
|
|
|
|
|
function parser_exit() {
|
|
|
|
|
if (typeof parser_callback !== 'function')
|
|
|
|
|
return;
|
|
|
|
|
try{
|
|
|
|
|
parser_callback();
|
|
|
|
|
} catch(err) {
|
|
|
|
|
stdio.write(io.stderr,'Shell: internal error in parser\n');
|
|
|
|
|
io.exit(1);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
function parser_run(cb) {
|
|
|
|
|
if (typeof cb === 'function')
|
|
|
|
|
parser_callback = cb;
|
|
|
|
|
var f = parser_files.shift();
|
|
|
|
|
if (!f) {
|
|
|
|
|
parser_exit();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
parser_parseFile(f);
|
|
|
|
|
}
|
|
|
|
|
function parser_stdin() {
|
|
|
|
|
parser_callback = function() {
|
|
|
|
|
io.exit(0);
|
|
|
|
|
}
|
|
|
|
|
parser_prepFile(io.stdin);
|
|
|
|
|
}
|
2023-12-14 07:19:07 +00:00
|
|
|
|
2023-12-20 10:30:06 +00:00
|
|
|
function exec_doCommand(cmd) {
|
|
|
|
|
exec_active = cmd;
|
|
|
|
|
if ((cmd.onlastsuccess && exec_last != 0) || (cmd.onlastfail && exec_last == 0)) {
|
|
|
|
|
exec_run();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
switch (cmd.args[0]) {
|
|
|
|
|
case 'if':
|
|
|
|
|
exec_conditionals.push(cmd);
|
|
|
|
|
exec_run();
|
|
|
|
|
return;
|
|
|
|
|
break;
|
|
|
|
|
case 'then':
|
|
|
|
|
if (exec_last == 0) {
|
|
|
|
|
exec_conditionals[exec_conditionals.length-1].conditional = true;
|
|
|
|
|
}else{
|
|
|
|
|
exec_conditionals[exec_conditionals.length-1].conditional = false;
|
|
|
|
|
exec_skipto = 'else';
|
2023-12-14 07:19:07 +00:00
|
|
|
}
|
2023-12-20 10:30:06 +00:00
|
|
|
exec_run();
|
|
|
|
|
return;
|
|
|
|
|
break;
|
|
|
|
|
case 'else':
|
|
|
|
|
if (exec_conditionals[exec_conditionals.length-1].conditional != false) {
|
|
|
|
|
exec_skipto = 'fi';
|
2023-12-14 07:19:07 +00:00
|
|
|
}
|
2023-12-20 10:30:06 +00:00
|
|
|
exec_run();
|
|
|
|
|
return;
|
|
|
|
|
break;
|
|
|
|
|
case 'fi':
|
|
|
|
|
exec_conditionals.pop();
|
|
|
|
|
exec_run();
|
|
|
|
|
return;
|
|
|
|
|
break;
|
|
|
|
|
case 'while':
|
|
|
|
|
case 'do':
|
|
|
|
|
case 'done':
|
|
|
|
|
exec_run();
|
|
|
|
|
return;
|
|
|
|
|
break;
|
|
|
|
|
default:;
|
|
|
|
|
}
|
|
|
|
|
var usebi = false;
|
|
|
|
|
var usebo = false;
|
|
|
|
|
if (cmd.stdin != '&0') {
|
|
|
|
|
switch (cmd.stdin) {
|
|
|
|
|
case '|':
|
|
|
|
|
exec_stdin_setOut();
|
|
|
|
|
usebi = true;
|
|
|
|
|
break;
|
|
|
|
|
case null:
|
|
|
|
|
exec_stdin_setNull();
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
exec_stdin_setFile(cmd.stdin);
|
|
|
|
|
break;
|
2023-12-14 07:19:07 +00:00
|
|
|
}
|
2023-12-20 10:30:06 +00:00
|
|
|
}else{
|
2023-12-21 00:05:14 +00:00
|
|
|
if (exec_closin) {
|
2023-12-20 10:30:06 +00:00
|
|
|
stdio.close(exec_io.stdin);
|
2023-12-21 00:05:14 +00:00
|
|
|
exec_closin = false;
|
2023-12-20 10:30:06 +00:00
|
|
|
}
|
|
|
|
|
exec_io.stdin = io.stdin;
|
|
|
|
|
}
|
|
|
|
|
if (cmd.stdout != '&1') {
|
|
|
|
|
switch (cmd.stdout) {
|
|
|
|
|
case '|':
|
|
|
|
|
exec_stdout_setBuffered();
|
|
|
|
|
usebo = true;
|
|
|
|
|
break;
|
|
|
|
|
case null:
|
|
|
|
|
exec_stdout_setNull();
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
exec_stdout_setFile(cmd.stdout);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}else{
|
2023-12-21 00:05:14 +00:00
|
|
|
if (exec_closout) {
|
2023-12-20 10:30:06 +00:00
|
|
|
stdio.close(exec_io.stdout);
|
2023-12-21 00:05:14 +00:00
|
|
|
exec_closout = false;
|
2023-12-20 10:30:06 +00:00
|
|
|
}
|
|
|
|
|
exec_io.stdout = io.stdout;
|
|
|
|
|
}
|
|
|
|
|
if (cmd.stderr != '&2') {
|
|
|
|
|
switch (cmd.stderr) {
|
|
|
|
|
case '&1':
|
|
|
|
|
exec_stderr_setOut();
|
|
|
|
|
break;
|
|
|
|
|
case null:
|
|
|
|
|
exec_stderr_setNull();
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
exec_stderr_setFile(cmd.stderr);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}else{
|
2023-12-21 00:05:14 +00:00
|
|
|
if (exec_closerr) {
|
2023-12-20 10:30:06 +00:00
|
|
|
stdio.close(exec_io.stderr);
|
2023-12-21 00:05:14 +00:00
|
|
|
exec_closerr = false;
|
2023-12-14 08:59:15 +00:00
|
|
|
}
|
2023-12-20 10:30:06 +00:00
|
|
|
exec_io.stderr = io.stderr;
|
2023-12-14 07:19:07 +00:00
|
|
|
}
|
2023-12-20 10:30:06 +00:00
|
|
|
if (exec_io.stdin == null) {
|
|
|
|
|
stdio.write(io.stderr,'could not open standard input for reading\n');
|
|
|
|
|
exec_setLast(1);
|
|
|
|
|
exec_run();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (exec_io.stdout == null) {
|
|
|
|
|
stdio.write(io.stderr,'could not open standard output for writing\n');
|
|
|
|
|
exec_setLast(1);
|
|
|
|
|
exec_run();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (exec_io.stderr == null) {
|
|
|
|
|
stdio.write(io.stderr,'could not open standard error for writing\n');
|
|
|
|
|
exec_setLast(1);
|
|
|
|
|
exec_run();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (builtins.indexOf(cmd.args[0]) > -1) {
|
|
|
|
|
exec_io.exit = io.exit;
|
|
|
|
|
let fn = builtins.indexOf(cmd.args[0]);
|
2023-11-26 09:54:37 +00:00
|
|
|
|
2023-12-20 10:30:06 +00:00
|
|
|
let r = builtins_func[fn](cmd.args,exec_io);
|
2023-12-14 14:44:44 +00:00
|
|
|
|
2023-12-20 10:30:06 +00:00
|
|
|
exec_setLast(r);
|
|
|
|
|
exec_run();
|
|
|
|
|
return;
|
|
|
|
|
}
|
2023-12-14 14:44:44 +00:00
|
|
|
|
2023-12-20 10:30:06 +00:00
|
|
|
if (!cmd.path) {
|
|
|
|
|
stdio.fprintf(io.stderr,'Shell: unknown command: %s\n',cmd.args[0]);
|
|
|
|
|
exec_setLast(1);
|
|
|
|
|
exec_run();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
var pid = stdlib.fork(env,exec_io,exec_doExec);
|
|
|
|
|
if (pid == 0) {
|
|
|
|
|
stdio.write(io.stderr,'Shell: internal error\n');
|
|
|
|
|
exec_setLast(1);
|
|
|
|
|
exec_run();
|
|
|
|
|
return;
|
|
|
|
|
}
|
2023-12-14 14:44:44 +00:00
|
|
|
|
2023-12-20 10:30:06 +00:00
|
|
|
stdlib.waitpid(pid,function(pid,ev) {
|
|
|
|
|
exec_setLast(ev);
|
|
|
|
|
exec_run();
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
function exec_doExec(env,io) {
|
|
|
|
|
var r = stdlib.exec(exec_active.path,exec_active.args,env,io);
|
|
|
|
|
if (r > 0)
|
|
|
|
|
return;
|
2023-12-14 14:44:44 +00:00
|
|
|
|
2023-12-20 10:30:06 +00:00
|
|
|
if (r == -1) {
|
|
|
|
|
stdlib.fprintf(io.stderr,'Shell: unknown command: %s\n',exec_active.args[0]);
|
|
|
|
|
io.exit(-1);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2023-12-14 14:44:44 +00:00
|
|
|
|
2023-12-20 10:30:06 +00:00
|
|
|
if (r == -2) {
|
|
|
|
|
stdio.fprintf(io.stderr,'Shell: error in command: %s\n',exec_active.args[0]);
|
|
|
|
|
io.exit(-1);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2023-12-14 14:44:44 +00:00
|
|
|
|
2023-12-20 10:30:06 +00:00
|
|
|
if (r == -3 || r == -4) {
|
|
|
|
|
stdio.fprintf(io.stderr,'Shell: not an executable file: %s\n',exec_active.args[0]);
|
|
|
|
|
io.exit(-3);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2023-12-14 14:44:44 +00:00
|
|
|
|
2023-12-20 10:30:06 +00:00
|
|
|
if (r == -5) {
|
|
|
|
|
stdio.fprintf(io.stderr,'Shell: invalid parser for file: %s\n',exec_active.args[0]);
|
|
|
|
|
io.exit(-3);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2023-12-14 14:44:44 +00:00
|
|
|
|
2023-12-20 10:30:06 +00:00
|
|
|
if (r == -6) {
|
|
|
|
|
stdio.fprintf(io.stderr,'Shell: no valid parser for file: %s\n',exec_active.args[0]);
|
|
|
|
|
io.exit(-3);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2023-12-16 04:30:29 +00:00
|
|
|
|
2023-12-20 10:30:06 +00:00
|
|
|
if (r == -7 || r == -8) {
|
|
|
|
|
stdio.fprintf(io.stderr,'Shell: failed to set uid/gid for: %s\n',exec_active.args[0]);
|
|
|
|
|
io.exit(-3);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (r<0) {
|
|
|
|
|
stdio.fprintf(io.stderr,'Shell: could not exec file: %s\n',exec_active.args[0]);
|
|
|
|
|
io.exit(-3);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
function exec_setLast(v) {
|
|
|
|
|
exec_last = parseInt(v);
|
|
|
|
|
env['?'] = exec_last.toString();
|
|
|
|
|
}
|
|
|
|
|
function exec_setCommand(txt) {
|
|
|
|
|
var args = clite.strToArgs(txt);
|
|
|
|
|
if (args.length < 1)
|
|
|
|
|
return;
|
|
|
|
|
args.forEach(function(val,i) {
|
|
|
|
|
args[i] = preprocess(val);
|
|
|
|
|
});
|
|
|
|
|
var cmd = {
|
|
|
|
|
args:[],
|
|
|
|
|
path:null,
|
|
|
|
|
stdin:'&0',
|
|
|
|
|
stdout:'&1',
|
|
|
|
|
stderr:'&2',
|
|
|
|
|
onlastsuccess:false,
|
|
|
|
|
onlastfail:false,
|
|
|
|
|
conditional:false
|
|
|
|
|
};
|
|
|
|
|
var c = structuredClone(cmd);
|
|
|
|
|
exec_cmds = [];
|
|
|
|
|
var fault = false;
|
|
|
|
|
var conds = [];
|
|
|
|
|
var loops = [];
|
|
|
|
|
for (var i=0; i<args.length; i++) {
|
|
|
|
|
if (args[i] == ';') {
|
|
|
|
|
if (c.args.length > 0) {
|
|
|
|
|
exec_cmds.push(c);
|
2023-12-15 04:56:19 +00:00
|
|
|
c = structuredClone(cmd);
|
|
|
|
|
}
|
2023-12-20 10:30:06 +00:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (args[i] == 'if') {
|
|
|
|
|
if (c.args.length > 0) {
|
|
|
|
|
exec_cmds.push(c);
|
2023-12-15 04:56:19 +00:00
|
|
|
c = structuredClone(cmd);
|
|
|
|
|
}
|
2023-12-20 10:30:06 +00:00
|
|
|
c.args.push(args[i]);
|
|
|
|
|
exec_cmds.push(c);
|
|
|
|
|
conds.push(c);
|
|
|
|
|
c = structuredClone(cmd);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (args[i] == 'then') {
|
|
|
|
|
if (c.args.length > 0) {
|
|
|
|
|
exec_cmds.push(c);
|
2023-12-15 04:56:19 +00:00
|
|
|
c = structuredClone(cmd);
|
|
|
|
|
}
|
2023-12-20 10:30:06 +00:00
|
|
|
c.args.push(args[i]);
|
|
|
|
|
exec_cmds.push(c);
|
|
|
|
|
if (conds.length < 1) {
|
|
|
|
|
fault = true;
|
|
|
|
|
}else{
|
|
|
|
|
conds[conds.length-1].args.push(c);
|
2023-12-15 04:56:19 +00:00
|
|
|
}
|
2023-12-20 10:30:06 +00:00
|
|
|
c = structuredClone(cmd);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (args[i] == 'else') {
|
|
|
|
|
if (c.args.length > 0) {
|
|
|
|
|
exec_cmds.push(c);
|
2023-12-15 04:56:19 +00:00
|
|
|
c = structuredClone(cmd);
|
|
|
|
|
}
|
2023-12-20 10:30:06 +00:00
|
|
|
c.args.push(args[i]);
|
|
|
|
|
exec_cmds.push(c);
|
|
|
|
|
if (conds.length < 1) {
|
|
|
|
|
fault = true;
|
|
|
|
|
}else{
|
|
|
|
|
conds[conds.length-1].args.push(c);
|
2023-12-15 04:56:19 +00:00
|
|
|
}
|
2023-12-20 10:30:06 +00:00
|
|
|
c = structuredClone(cmd);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (args[i] == 'fi') {
|
|
|
|
|
if (c.args.length > 0) {
|
|
|
|
|
exec_cmds.push(c);
|
2023-12-15 04:56:19 +00:00
|
|
|
c = structuredClone(cmd);
|
|
|
|
|
}
|
2023-12-20 10:30:06 +00:00
|
|
|
c.args.push(args[i]);
|
|
|
|
|
exec_cmds.push(c);
|
|
|
|
|
if (conds.length < 1) {
|
|
|
|
|
fault = true;
|
|
|
|
|
}else{
|
|
|
|
|
conds[conds.length-1].args.push(c);
|
|
|
|
|
conds.pop();
|
2023-12-14 14:44:44 +00:00
|
|
|
}
|
2023-12-20 10:30:06 +00:00
|
|
|
c = structuredClone(cmd);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (args[i] == 'while') {
|
|
|
|
|
if (c.args.length > 0) {
|
|
|
|
|
exec_cmds.push(c);
|
2023-12-14 14:44:44 +00:00
|
|
|
c = structuredClone(cmd);
|
|
|
|
|
}
|
2023-12-20 10:30:06 +00:00
|
|
|
c.args.push(args[i]);
|
|
|
|
|
exec_cmds.push(c);
|
|
|
|
|
loops.push(c);
|
|
|
|
|
c = structuredClone(cmd);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (args[i] == 'do') {
|
|
|
|
|
if (c.args.length > 0) {
|
|
|
|
|
exec_cmds.push(c);
|
2023-12-14 14:44:44 +00:00
|
|
|
c = structuredClone(cmd);
|
|
|
|
|
}
|
|
|
|
|
c.args.push(args[i]);
|
2023-12-20 10:30:06 +00:00
|
|
|
exec_cmds.push(c);
|
|
|
|
|
if (loops.length < 1) {
|
2023-12-14 14:44:44 +00:00
|
|
|
fault = true;
|
|
|
|
|
}else{
|
2023-12-20 10:30:06 +00:00
|
|
|
loops[loops.length-1].args.push(c);
|
2023-12-14 14:44:44 +00:00
|
|
|
}
|
2023-12-20 10:30:06 +00:00
|
|
|
c = structuredClone(cmd);
|
|
|
|
|
continue;
|
2023-12-14 14:44:44 +00:00
|
|
|
}
|
2023-12-20 10:30:06 +00:00
|
|
|
if (args[i] == 'done') {
|
|
|
|
|
if (c.args.length > 0) {
|
|
|
|
|
exec_cmds.push(c);
|
|
|
|
|
c = structuredClone(cmd);
|
2023-12-14 14:44:44 +00:00
|
|
|
}
|
2023-12-20 10:30:06 +00:00
|
|
|
c.args.push(args[i]);
|
|
|
|
|
exec_cmds.push(c);
|
|
|
|
|
if (loops.length < 1) {
|
|
|
|
|
fault = true;
|
2023-12-14 14:44:44 +00:00
|
|
|
}else{
|
2023-12-20 10:30:06 +00:00
|
|
|
loops[loops.length-1].args.push(c);
|
|
|
|
|
loops.pop();
|
2023-12-14 14:44:44 +00:00
|
|
|
}
|
2023-12-20 10:30:06 +00:00
|
|
|
c = structuredClone(cmd);
|
|
|
|
|
continue;
|
2023-12-14 14:44:44 +00:00
|
|
|
}
|
2023-12-20 10:30:06 +00:00
|
|
|
if (args[i] == '|') {
|
|
|
|
|
c.stdout = '|';
|
|
|
|
|
exec_cmds.push(c);
|
|
|
|
|
c = structuredClone(cmd);
|
|
|
|
|
c.stdin = '|';
|
|
|
|
|
continue;
|
2023-12-14 14:44:44 +00:00
|
|
|
}
|
2023-12-20 10:30:06 +00:00
|
|
|
if (args[i] == '||') {
|
|
|
|
|
exec_cmds.push(c);
|
|
|
|
|
c = structuredClone(cmd);
|
|
|
|
|
c.onlastfail = true;
|
|
|
|
|
continue;
|
2023-12-14 14:44:44 +00:00
|
|
|
}
|
2023-12-20 10:30:06 +00:00
|
|
|
if (args[i] == '&&') {
|
|
|
|
|
exec_cmds.push(c);
|
|
|
|
|
c = structuredClone(cmd);
|
|
|
|
|
c.onlastsuccess = true;
|
|
|
|
|
continue;
|
2023-12-14 14:44:44 +00:00
|
|
|
}
|
2023-12-20 10:30:06 +00:00
|
|
|
if (args[i] == '>') {
|
|
|
|
|
i++;
|
|
|
|
|
c.stdout = clite.resolvePath(args[i]);
|
|
|
|
|
if (c.stdout == '/dev/null')
|
|
|
|
|
c.stdout = null;
|
|
|
|
|
continue;
|
2023-12-14 14:44:44 +00:00
|
|
|
}
|
2023-12-20 10:30:06 +00:00
|
|
|
if (args[i] == '2>&1') {
|
|
|
|
|
c.stderr = '&1';
|
|
|
|
|
continue;
|
2023-12-14 14:44:44 +00:00
|
|
|
}
|
2023-12-20 10:30:06 +00:00
|
|
|
if (args[i] == '>>') {
|
|
|
|
|
i++;
|
|
|
|
|
c.stdout = clite.resolvePath(args[i]);
|
|
|
|
|
if (c.stdout == '/dev/null') {
|
|
|
|
|
c.stdout = null;
|
|
|
|
|
}else{
|
|
|
|
|
c.stdout = '+'+c.stdout;
|
2023-12-15 04:56:19 +00:00
|
|
|
}
|
2023-12-20 10:30:06 +00:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (args[i] == '<') {
|
|
|
|
|
i++;
|
|
|
|
|
c.stdin = clite.resolvePath(args[i]);
|
|
|
|
|
if (c.stdin == '/dev/null')
|
|
|
|
|
c.stdin = null;
|
|
|
|
|
continue;
|
2023-12-15 04:56:19 +00:00
|
|
|
}
|
2023-12-20 10:30:06 +00:00
|
|
|
c.args.push(args[i]);
|
|
|
|
|
}
|
|
|
|
|
if (conds.length > 0)
|
|
|
|
|
fault = true;
|
|
|
|
|
if (loops.length > 0)
|
|
|
|
|
fault = true;
|
|
|
|
|
if (c.args.length > 0)
|
|
|
|
|
exec_cmds.push(c);
|
|
|
|
|
exec_cmds.forEach(function(c,i) {
|
|
|
|
|
if (c.args.length < 1) {
|
|
|
|
|
fault = true;
|
2023-12-14 14:44:44 +00:00
|
|
|
return;
|
|
|
|
|
}
|
2023-12-20 10:30:06 +00:00
|
|
|
c.args[0] = c.args[0].trim();
|
|
|
|
|
c.path = resolvePATH(c.args[0]);
|
|
|
|
|
});
|
|
|
|
|
if (fault) {
|
|
|
|
|
stdio.write(io.stderr,'Shell: unable to parse command\n');
|
|
|
|
|
exec_exit();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
exec_io.pid = io.pid;
|
|
|
|
|
exec_io.stdin = io.stdin;
|
|
|
|
|
exec_io.stdout = io.stdout;
|
|
|
|
|
exec_io.stderr = io.stderr;
|
|
|
|
|
exec_io.exit = null; // filled in by fork()
|
|
|
|
|
exec_io.include = null; // filled in by fork()
|
|
|
|
|
exec_last = 0;
|
|
|
|
|
}
|
|
|
|
|
function exec_stdin_setFile(path) {
|
2023-12-21 00:05:14 +00:00
|
|
|
if (exec_closin) {
|
2023-12-20 10:30:06 +00:00
|
|
|
stdio.close(exec_io.stdin);
|
2023-12-21 00:05:14 +00:00
|
|
|
exec_closin = false;
|
2023-12-20 10:30:06 +00:00
|
|
|
}
|
|
|
|
|
exec_io.stdin = stdio.open(path,stdio.flags.O_RDONLY);
|
2023-12-21 00:05:14 +00:00
|
|
|
exec_closin = true;
|
2023-12-20 10:30:06 +00:00
|
|
|
}
|
|
|
|
|
function exec_stdin_setNull() {
|
2023-12-21 00:05:14 +00:00
|
|
|
if (exec_closin) {
|
2023-12-20 10:30:06 +00:00
|
|
|
stdio.close(exec_io.stdin);
|
2023-12-21 00:05:14 +00:00
|
|
|
exec_closin = false;
|
2023-12-20 10:30:06 +00:00
|
|
|
}
|
|
|
|
|
exec_io.stdin = stdio.open('/dev/null',stdio.flags.O_RDONLY);
|
2023-12-21 00:05:14 +00:00
|
|
|
exec_closin = true;
|
2023-12-20 10:30:06 +00:00
|
|
|
}
|
|
|
|
|
function exec_stdin_setOut() {
|
2023-12-21 00:05:14 +00:00
|
|
|
if (exec_closin) {
|
2023-12-20 10:30:06 +00:00
|
|
|
stdio.close(exec_io.stdin);
|
2023-12-21 00:05:14 +00:00
|
|
|
exec_closin = false;
|
2023-12-20 10:30:06 +00:00
|
|
|
}
|
|
|
|
|
if (exec_bufferout) {
|
|
|
|
|
exec_io.stdout = null;
|
2023-12-21 00:05:14 +00:00
|
|
|
exec_closout = false;
|
2023-12-20 10:30:06 +00:00
|
|
|
exec_bufferin = exec_bufferout;
|
|
|
|
|
exec_bufferout = null;
|
|
|
|
|
exec_io.stdin = exec_bufferin;
|
|
|
|
|
stdio.seek(exec_io.stdin,0);
|
2023-12-21 00:05:14 +00:00
|
|
|
exec_closin = true;
|
2023-12-20 10:30:06 +00:00
|
|
|
}else{
|
|
|
|
|
exec_stdin_setNull();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
function exec_stdout_setBuffered() {
|
2023-12-21 00:05:14 +00:00
|
|
|
if (exec_closout) {
|
2023-12-20 10:30:06 +00:00
|
|
|
stdio.close(exec_io.stdout);
|
2023-12-21 00:05:14 +00:00
|
|
|
exec_closout = false;
|
2023-12-20 10:30:06 +00:00
|
|
|
if (exec_bufferout)
|
|
|
|
|
exec_bufferout = null;
|
|
|
|
|
}
|
|
|
|
|
exec_bufferout = stdio.mkstemp('/tmp/shell-XXXXXX');
|
|
|
|
|
exec_io.stdout = exec_bufferout;
|
2023-12-21 00:05:14 +00:00
|
|
|
exec_closout = false;
|
2023-12-20 10:30:06 +00:00
|
|
|
}
|
|
|
|
|
function exec_stdout_setFile(path) {
|
2023-12-21 00:05:14 +00:00
|
|
|
if (exec_closout) {
|
2023-12-20 10:30:06 +00:00
|
|
|
stdio.close(exec_io.stdout);
|
2023-12-21 00:05:14 +00:00
|
|
|
exec_closout = false;
|
2023-12-20 10:30:06 +00:00
|
|
|
}
|
|
|
|
|
var flags = stdio.flags.O_WRONLY|stdio.flags.O_CREAT|stdio.flags.O_SYNC;
|
|
|
|
|
var p = path;
|
|
|
|
|
if (path[0] == '+') {
|
|
|
|
|
flags |= stdio.flags.O_APPEND;
|
|
|
|
|
p = path.substring(1);
|
|
|
|
|
}else{
|
|
|
|
|
flags |= stdio.flags.O_TRUNC;
|
|
|
|
|
}
|
|
|
|
|
exec_io.stdout = stdio.open(p,flags);
|
2023-12-21 00:05:14 +00:00
|
|
|
exec_closout = true;
|
2023-12-20 10:30:06 +00:00
|
|
|
}
|
|
|
|
|
function exec_stdout_setNull() {
|
2023-12-21 00:05:14 +00:00
|
|
|
if (exec_closout) {
|
2023-12-20 10:30:06 +00:00
|
|
|
stdio.close(exec_io.stdout);
|
2023-12-21 00:05:14 +00:00
|
|
|
exec_closout = false;
|
2023-12-20 10:30:06 +00:00
|
|
|
}
|
|
|
|
|
exec_io.stdout = stdio.open('/dev/null',stdio.flags.O_WRONLY);
|
2023-12-21 00:05:14 +00:00
|
|
|
exec_closout = true;
|
2023-12-20 10:30:06 +00:00
|
|
|
}
|
|
|
|
|
function exec_stderr_setFile(path) {
|
2023-12-21 00:05:14 +00:00
|
|
|
if (exec_closerr) {
|
2023-12-20 10:30:06 +00:00
|
|
|
stdio.close(exec_io.stderr);
|
2023-12-21 00:05:14 +00:00
|
|
|
exec_closerr = false;
|
2023-12-20 10:30:06 +00:00
|
|
|
}
|
|
|
|
|
var flags = stdio.flags.O_WRONLY|stdio.flags.O_CREAT|stdio.flags.O_SYNC;
|
|
|
|
|
var p = path;
|
|
|
|
|
if (path[0] == '+') {
|
|
|
|
|
flags |= stdio.flags.O_APPEND;
|
|
|
|
|
p = path.substring(1);
|
|
|
|
|
}else{
|
|
|
|
|
flags |= stdio.flags.O_TRUNC;
|
|
|
|
|
}
|
|
|
|
|
exec_io.stderr = stdio.open(p,flags);
|
2023-12-21 00:05:14 +00:00
|
|
|
exec_closerr = true;
|
2023-12-20 10:30:06 +00:00
|
|
|
}
|
|
|
|
|
function exec_stderr_setNull() {
|
2023-12-21 00:05:14 +00:00
|
|
|
if (exec_closerr) {
|
2023-12-20 10:30:06 +00:00
|
|
|
stdio.close(exec_io.stderr);
|
2023-12-21 00:05:14 +00:00
|
|
|
exec_closerr = false;
|
2023-12-20 10:30:06 +00:00
|
|
|
}
|
|
|
|
|
exec_io.stderr = stdio.open('/dev/null',stdio.flags.O_WRONLY);
|
2023-12-21 00:05:14 +00:00
|
|
|
exec_closerr = true;
|
2023-12-20 10:30:06 +00:00
|
|
|
}
|
|
|
|
|
function exec_stderr_setOut() {
|
2023-12-21 00:05:14 +00:00
|
|
|
if (exec_closerr) {
|
2023-12-20 10:30:06 +00:00
|
|
|
stdio.close(exec_io.stderr);
|
2023-12-21 00:05:14 +00:00
|
|
|
exec_closerr = false;
|
2023-12-20 10:30:06 +00:00
|
|
|
}
|
|
|
|
|
exec_io.stderr = exec_io.stdout;
|
2023-12-21 00:05:14 +00:00
|
|
|
exec_closerr = exec_closout;
|
2023-12-20 10:30:06 +00:00
|
|
|
}
|
|
|
|
|
function exec_exit() {
|
2023-12-21 00:05:14 +00:00
|
|
|
if (exec_closin) {
|
2023-12-20 10:30:06 +00:00
|
|
|
stdio.close(exec_io.stdin);
|
2023-12-21 00:05:14 +00:00
|
|
|
exec_closin = false;
|
2023-12-20 10:30:06 +00:00
|
|
|
}
|
|
|
|
|
var out = '';
|
|
|
|
|
if (exec_bufferout)
|
|
|
|
|
out = stdio.readAll(exec_bufferout);
|
2023-12-21 00:05:14 +00:00
|
|
|
if (exec_closout) {
|
2023-12-20 10:30:06 +00:00
|
|
|
stdio.close(exec_io.stdout);
|
2023-12-21 00:05:14 +00:00
|
|
|
exec_closout = false;
|
2023-12-14 14:44:44 +00:00
|
|
|
}
|
2023-12-21 00:05:14 +00:00
|
|
|
if (exec_closerr) {
|
2023-12-20 10:30:06 +00:00
|
|
|
stdio.close(exec_io.stderr);
|
2023-12-21 00:05:14 +00:00
|
|
|
exec_closerr = false;
|
2023-12-20 10:30:06 +00:00
|
|
|
}
|
|
|
|
|
exec_active = null;
|
|
|
|
|
exec_cmds = [];
|
|
|
|
|
if (typeof exec_callback !== 'function')
|
|
|
|
|
return;
|
|
|
|
|
try{
|
|
|
|
|
exec_callback(out);
|
|
|
|
|
} catch(err) {
|
|
|
|
|
console.log(err.fileName+':'+err.lineNumber+':'+err.columnNumber+':'+err.message);
|
|
|
|
|
stdio.write(io.stderr,'Shell: internal error in command execution\n');
|
|
|
|
|
io.exit(1);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
function exec_run(cb) {
|
|
|
|
|
if (typeof cb === 'function')
|
|
|
|
|
exec_callback = cb;
|
|
|
|
|
var c;
|
|
|
|
|
if (exec_skipto !== null) {
|
|
|
|
|
if (exec_skipto == 'fi') {
|
|
|
|
|
while ((c = exec_cmds.shift()) != null) {
|
|
|
|
|
if (c.args[0] == 'fi')
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}else if (exec_skipto == 'else') {
|
|
|
|
|
while ((c = exec_cmds.shift()) != null) {
|
|
|
|
|
if (c.args[0] == 'else' || c.args[0] == 'fi')
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
exec_skipto = null;
|
|
|
|
|
}else{
|
|
|
|
|
c = exec_cmds.shift();
|
|
|
|
|
}
|
|
|
|
|
if (!c) {
|
|
|
|
|
exec_exit();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
exec_doCommand(c);
|
|
|
|
|
}
|
2023-12-14 14:44:44 +00:00
|
|
|
|
2023-12-13 03:42:57 +00:00
|
|
|
function help() {
|
|
|
|
|
stdio.write(io.stdout,`
|
|
|
|
|
sh - command interpreter (shell)
|
|
|
|
|
Usage: sh [OPTION] [FILE]
|
|
|
|
|
|
|
|
|
|
Options:
|
|
|
|
|
-? Print this help information
|
|
|
|
|
|
|
|
|
|
`);
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-17 04:57:15 +00:00
|
|
|
function doShellExit(v) {
|
2023-12-20 10:30:06 +00:00
|
|
|
history_save();
|
2023-12-17 04:57:15 +00:00
|
|
|
stdio.write(io.stdout,'\n');
|
|
|
|
|
has_exited = true;
|
|
|
|
|
io.exit(v);
|
|
|
|
|
}
|
|
|
|
|
|
2023-11-25 10:43:51 +00:00
|
|
|
function resolvePATH(txt) {
|
2023-12-15 04:56:19 +00:00
|
|
|
// special case of test command
|
|
|
|
|
if (txt == '[')
|
|
|
|
|
txt = 'test';
|
2023-11-25 10:43:51 +00:00
|
|
|
if (typeof env.PATH === 'undefined')
|
|
|
|
|
env.PATH = '/bin';
|
|
|
|
|
var paths = env.PATH.split(':');
|
|
|
|
|
var path = null;
|
|
|
|
|
paths.forEach(function(p) {
|
|
|
|
|
if (path)
|
|
|
|
|
return;
|
2023-11-27 09:01:52 +00:00
|
|
|
var rp = clite.resolvePath(txt,p);
|
2023-12-14 14:44:44 +00:00
|
|
|
var st = stdio.stat(rp);
|
2023-12-04 11:18:35 +00:00
|
|
|
if (st) {
|
2023-11-25 10:43:51 +00:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-13 03:42:57 +00:00
|
|
|
function tabfill(c) {
|
2023-11-27 09:01:52 +00:00
|
|
|
var parts = clite.strToArgs(c);
|
2023-11-26 09:54:37 +00:00
|
|
|
var ai = parts.length-1;
|
|
|
|
|
if (ai < 0)
|
2023-12-13 03:42:57 +00:00
|
|
|
return null;
|
2023-11-26 09:54:37 +00:00
|
|
|
var a = parts[ai];
|
|
|
|
|
var add = '';
|
|
|
|
|
if (ai == 0) {
|
|
|
|
|
// test for shell macros/builtins
|
2023-12-20 10:30:06 +00:00
|
|
|
builtins.forEach(function(key) {
|
2023-11-26 09:54:37 +00:00
|
|
|
if (add == '' && key.substring(0,a.length) == a) {
|
|
|
|
|
add = key.substring(a.length);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
if (add == '') {
|
|
|
|
|
// test for commands
|
2023-12-18 10:46:56 +00:00
|
|
|
let pparts = env.PATH.split(':');
|
2023-11-26 09:54:37 +00:00
|
|
|
pparts.forEach(function(pp) {
|
|
|
|
|
if (add != '')
|
|
|
|
|
return;
|
2023-12-18 10:46:56 +00:00
|
|
|
let fd = stdio.open('/bin',stdio.flags.O_SEARCH|stdio.flags.O_DIRECTORY);
|
|
|
|
|
let f = null;
|
2023-11-26 09:54:37 +00:00
|
|
|
while (add == '' && (f = stdio.read(fd)) != null) {
|
|
|
|
|
if (f.substring(0,a.length) == a) {
|
|
|
|
|
add = f.substring(a.length)+' ';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
stdio.close(fd);
|
|
|
|
|
});
|
|
|
|
|
}
|
2023-12-18 10:46:56 +00:00
|
|
|
}else if (a != '') {
|
|
|
|
|
let p = clite.resolvePath(a);
|
|
|
|
|
if (p[0] == '/') {
|
|
|
|
|
let d = stdlib.dirname(p);
|
|
|
|
|
let b = stdlib.basename(p);
|
|
|
|
|
if (d == '')
|
|
|
|
|
d = '/';
|
|
|
|
|
let fd = stdio.open(d,stdio.flags.O_SEARCH|stdio.flags.O_DIRECTORY);
|
|
|
|
|
if (fd) {
|
|
|
|
|
let f = null;
|
|
|
|
|
while (add == '' && (f = stdio.read(fd)) != null) {
|
|
|
|
|
if (f.substring(0,b.length) == b) {
|
|
|
|
|
add = f.substring(b.length);
|
|
|
|
|
let fp = d+'/'+f;
|
|
|
|
|
let st = stdio.stat(fp);
|
|
|
|
|
if (st && st.type != stdio.types.FT_DIR)
|
|
|
|
|
add += ' ';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
stdio.close(fd);
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-11-26 09:54:37 +00:00
|
|
|
}
|
|
|
|
|
if (add == '')
|
2023-12-13 03:42:57 +00:00
|
|
|
return null;
|
|
|
|
|
stdio.write(io.stdout,'\b'+add);
|
|
|
|
|
return c+add;
|
2023-11-26 09:54:37 +00:00
|
|
|
}
|
|
|
|
|
|
2023-12-12 08:39:45 +00:00
|
|
|
function writePrompt() {
|
|
|
|
|
// generate the prompt
|
|
|
|
|
var p = env.PS1;
|
|
|
|
|
if (typeof p === 'undefined')
|
|
|
|
|
p = '${USER}:${PWD}'
|
|
|
|
|
|
2023-12-13 03:42:57 +00:00
|
|
|
var prompt = preprocess(p);
|
2023-12-12 08:39:45 +00:00
|
|
|
if (stdlib.getuid() == 0) {
|
|
|
|
|
prompt += '# ';
|
|
|
|
|
}else{
|
|
|
|
|
prompt += '$ ';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
stdio.write(io.stdout,prompt);
|
2023-11-25 10:43:51 +00:00
|
|
|
}
|
|
|
|
|
|
2023-12-20 10:30:06 +00:00
|
|
|
function inputProcess(str) {
|
|
|
|
|
let c = history_getCurrent();
|
|
|
|
|
switch (str) {
|
|
|
|
|
case String.fromCharCode(4):
|
|
|
|
|
case 4:
|
|
|
|
|
term.ttyctrl('raw',false);
|
|
|
|
|
doShellExit(0);
|
|
|
|
|
break;
|
|
|
|
|
case '\t': // tab
|
|
|
|
|
case 9:
|
|
|
|
|
var ct = tabfill(c);
|
|
|
|
|
if (ct != null) {
|
|
|
|
|
c = ct;
|
|
|
|
|
}else{
|
|
|
|
|
stdio.write(io.stdout,'\b \b');
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case '\n': // enter
|
|
|
|
|
term.ttyctrl('raw',false);
|
|
|
|
|
history_add(c);
|
|
|
|
|
history_resetCurrent();
|
|
|
|
|
exec_setCommand(c);
|
|
|
|
|
exec_run(inputRead);
|
2023-11-27 11:46:33 +00:00
|
|
|
return;
|
2023-12-20 10:30:06 +00:00
|
|
|
break;
|
|
|
|
|
case '\b':
|
|
|
|
|
case 8:
|
|
|
|
|
if (c.length > 0) {
|
|
|
|
|
c = c.substring(0,c.length-1);
|
|
|
|
|
stdio.write(io.stdout,'\b \b');
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case -3: // down arrow
|
|
|
|
|
var ct = history_down();
|
|
|
|
|
if (ct != null) {
|
|
|
|
|
for (var i=0; i<c.length; i++) {
|
2023-12-18 10:46:56 +00:00
|
|
|
stdio.write(io.stdout,'\b \b');
|
2023-12-13 03:42:57 +00:00
|
|
|
}
|
2023-12-20 10:30:06 +00:00
|
|
|
c = ct;
|
|
|
|
|
stdio.write(io.stdout,c);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case -4: // up arrow
|
|
|
|
|
var ct = history_up();
|
|
|
|
|
if (ct != null) {
|
|
|
|
|
for (var i=0; i<c.length; i++) {
|
2023-12-13 03:42:57 +00:00
|
|
|
stdio.write(io.stdout,'\b \b');
|
|
|
|
|
}
|
2023-12-20 10:30:06 +00:00
|
|
|
c = ct;
|
|
|
|
|
stdio.write(io.stdout,c);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
if (typeof str === 'string' && str.length == 1) {
|
|
|
|
|
c += str;
|
2023-12-13 03:42:57 +00:00
|
|
|
}
|
|
|
|
|
}
|
2023-12-20 10:30:06 +00:00
|
|
|
history_setCurrent(c);
|
|
|
|
|
stdio.read(io.stdin,inputProcess);
|
|
|
|
|
}
|
2023-12-13 03:42:57 +00:00
|
|
|
|
2023-12-20 10:30:06 +00:00
|
|
|
function inputRead() {
|
|
|
|
|
if (has_exited)
|
|
|
|
|
return;
|
2023-12-13 03:42:57 +00:00
|
|
|
// write the prompt
|
2023-12-12 08:39:45 +00:00
|
|
|
writePrompt();
|
2023-12-13 03:42:57 +00:00
|
|
|
// set tty to raw mode
|
|
|
|
|
term.ttyctrl('raw',true);
|
2023-11-25 10:43:51 +00:00
|
|
|
// then read from stdin
|
2023-12-13 03:42:57 +00:00
|
|
|
stdio.read(io.stdin,inputProcess);
|
2023-11-25 10:43:51 +00:00
|
|
|
}
|
|
|
|
|
|
2023-12-19 04:36:09 +00:00
|
|
|
function main(argc,argv) {
|
2023-12-13 03:42:57 +00:00
|
|
|
var f = null;
|
|
|
|
|
var s = false;
|
2023-12-19 04:36:09 +00:00
|
|
|
for (var i=1; i<argc; i++) {
|
|
|
|
|
if (argv[i][0] == '-') {
|
|
|
|
|
for (var j=1; j<argv[i].length; j++) {
|
|
|
|
|
switch (argv[i][j]) {
|
2023-12-13 03:42:57 +00:00
|
|
|
case '?':
|
|
|
|
|
help();
|
|
|
|
|
return 0;
|
|
|
|
|
break;
|
|
|
|
|
case 's':
|
|
|
|
|
s = true;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
2023-12-19 04:36:09 +00:00
|
|
|
stdio.fprintf(io.stderr,'unknown argument -%c\n',argv[i][j]);
|
2023-12-13 03:42:57 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}else if (f == null) {
|
2023-12-19 04:36:09 +00:00
|
|
|
f = clite.resolvePath(argv[i]);
|
2023-12-13 03:42:57 +00:00
|
|
|
}else{
|
2023-12-19 04:36:09 +00:00
|
|
|
stdio.fprintf(io.stderr,'unknown argument - %s\n',argv[i]);
|
2023-12-13 03:42:57 +00:00
|
|
|
}
|
2023-11-26 02:18:48 +00:00
|
|
|
}
|
2023-12-13 03:42:57 +00:00
|
|
|
|
2023-12-19 04:36:09 +00:00
|
|
|
// if argv[0] isn't the shell itself, then we're running a shell script
|
|
|
|
|
if (!f && argv[0] != '/bin/sh' && argv[0] != 'sh') {
|
|
|
|
|
f = clite.resolvePath(argv[0]);
|
2023-12-14 08:59:15 +00:00
|
|
|
if (!f)
|
|
|
|
|
return 1;
|
|
|
|
|
// make the arguments readable by the shell script
|
2023-12-19 04:36:09 +00:00
|
|
|
env['#'] = argc.toString();
|
|
|
|
|
for (var i=0; i<argc; i++) {
|
|
|
|
|
env[i.toString()] = argv[i];
|
2023-12-14 08:59:15 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-13 03:42:57 +00:00
|
|
|
// run a shell script if one is specified
|
|
|
|
|
if (f != null) {
|
2023-12-20 10:30:06 +00:00
|
|
|
parser_queue(f);
|
|
|
|
|
parser_run(function() {
|
2023-12-13 03:42:57 +00:00
|
|
|
io.exit(0);
|
|
|
|
|
});
|
|
|
|
|
// run a shell script from stdin
|
|
|
|
|
}else if (!stdio.isatty(io.stdin)) {
|
|
|
|
|
if (!s)
|
|
|
|
|
return 0;
|
2023-12-20 10:30:06 +00:00
|
|
|
parser_stdin();
|
2023-12-13 03:42:57 +00:00
|
|
|
// otherwise we have an interactive shell
|
|
|
|
|
// so run /etc/shrc and ~/.shrc
|
|
|
|
|
}else{
|
2023-12-20 10:30:06 +00:00
|
|
|
parser_queue('/etc/shrc');
|
|
|
|
|
parser_queue(env.HOME+'/.shrc');
|
|
|
|
|
parser_run(function() {
|
|
|
|
|
history_clear();
|
|
|
|
|
history_load();
|
2023-12-13 03:42:57 +00:00
|
|
|
inputRead();
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
2023-11-25 10:43:51 +00:00
|
|
|
|
2023-12-19 04:36:09 +00:00
|
|
|
return main(args.length,args);
|
2023-11-25 10:43:51 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
}
|