improved shell script parser

This commit is contained in:
Lisa Milne 2023-12-14 17:19:07 +10:00
parent 409470d0bc
commit 376d425330
3 changed files with 94 additions and 40 deletions

View file

@ -326,8 +326,7 @@ guest:x:1:
clite.log.write('shell config failure');
return false;
}
n.data.content =`
#!/bin/sh
n.data.content =`#!/bin/sh
cat /etc/greeting
`;
n.perms = '-rwxr-xr-x';
@ -924,8 +923,7 @@ clite.user = {
n.perms = '-rwx------';
n.uid = 1;
n.gid = 1;
n.data.content = `
#!/bin/sh
n.data.content = `#!/bin/sh
cat -l /usr/share/introduction
`;
}

View file

@ -60,7 +60,7 @@ return Object.create({
},
stat:function(path) {
var fd = clite.io.open(io.pid,path,clite.io.flags.O_RDONLY);
var fd = clite.io.open(io.pid,path,clite.io.flags.O_RDONLY|clite.io.flags.O_NONBLOCK);
if (!fd)
return null;
var st = clite.io.fstatat(io.pid,fd,0);
@ -69,7 +69,7 @@ return Object.create({
},
lstat:function(path) {
var fd = clite.io.open(io.pid,path,clite.io.flags.O_RDONLY|clite.io.flags.O_NOFOLLOW);
var fd = clite.io.open(io.pid,path,clite.io.flags.O_RDONLY|clite.io.flags.O_NOFOLLOW|clite.io.flags.O_NONBLOCK);
if (!fd)
return null;
var st = clite.io.fstatat(io.pid,fd,clite.io.flags.AT_SYMLINK_NOFOLLOW);

View file

@ -123,7 +123,80 @@ clite.commands.load('sh',function(args,env,io) {
history.current = '';
history.index = 0;
}
}
};
var parser = {
files:[],
callback:null,
queue:function(file) {
parser.files.push(file);
},
internal:{
lines:[],
parseFile:function(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.internal.prepFile);
if (!fd)
parser.run();
},
prepFile:function(fd) {
var data = stdio.readAll(fd);
stdio.close(fd);
if (!data) {
parser.run();
return;
}
parser.internal.lines = data.split('\n');
if (parser.internal.lines.length < 1) {
parser.run();
return;
}
parser.internal.parseLine();
},
parseLine:function() {
var l = parser.internal.lines.shift();
if (l == null) {
parser.run();
return;
}
if (l[0] == '#') {
parser.internal.parseLine();
return;
}
run(l,parser.internal.parseLine);
}
},
exit:function() {
if (typeof parser.callback === 'function') {
try{
parser.callback();
} catch(err) {
stdio.write(io.stderr,'Shell: internal error in parser\n');
io.exit(1);
return;
}
}
},
run:function(cb) {
if (typeof cb === 'function')
parser.callback = cb;
var f = parser.files.shift();
if (!f) {
parser.exit();
return;
}
parser.internal.parseFile(f);
}
};
function help() {
stdio.write(io.stdout,`
@ -245,19 +318,10 @@ Options:
return c+add;
}
function parseScript(fd) {
var l;
while ((l = stdio.readLine(fd)) != null) {
if (l[0] == '#')
continue;
run(l,false);
}
}
function run(txt,interactive) {
function run(txt,cb) {
if (txt.length < 1) {
if (interactive)
inputRead();
if (typeof cb === 'function')
cb();
return;
}
history.add(txt);
@ -282,16 +346,16 @@ Options:
if (typeof macro[args[0]] != 'undefined') {
fio.exit = io.exit;
var r = macro[args[0]](args,fio);
if (interactive)
inputRead();
if (typeof cb === 'function')
cb();
return;
}
var path = resolvePATH(args[0]);
if (!path) {
stdio.fprintf(io.stderr,'Shell: unknown command: %s\n',args[0]);
if (interactive)
inputRead();
if (typeof cb === 'function')
cb();
return;
}
@ -318,13 +382,13 @@ Options:
var pid = stdlib.fork(env,fio,execFunc);
if (pid == 0) {
stdio.write(io.stderr,'Shell: internal error\n');
if (interactive)
inputRead();
if (typeof cb === 'function')
cb();
return;
}
// TODO: if we're not interactive, we still want to waitpid
if (interactive)
stdlib.waitpid(pid,inputRead);
if (typeof cb === 'function')
stdlib.waitpid(pid,cb);
}
function writePrompt() {
@ -362,7 +426,7 @@ Options:
break;
case '\n': // enter
term.ttyctrl('raw',false);
run(c,true);
run(c,inputRead);
c = '';
cc = 0;
return;
@ -463,17 +527,9 @@ Options:
// otherwise we have an interactive shell
// so run /etc/shrc and ~/.shrc
}else{
var fd = stdio.open('/etc/shrc',stdio.flags.O_RDONLY|stdio.flags.O_SYNC);
if (fd) {
parseScript(fd);
stdio.close(fd);
}
fd = stdio.open(env.HOME+'/.shrc',stdio.flags.O_RDONLY|stdio.flags.O_SYNC);
if (fd) {
parseScript(fd);
stdio.close(fd);
}
stdlib.waitall(function() {
parser.queue('/etc/shrc');
parser.queue(env.HOME+'/.shrc');
parser.run(function() {
history.clear();
inputRead();
});