conditional expressions in shell and scripts

This commit is contained in:
Lisa Milne 2023-12-15 14:56:19 +10:00
parent 23f2408b0e
commit c56fe770b9
3 changed files with 196 additions and 10 deletions

View file

@ -1655,7 +1655,7 @@ Options:
if (args.length > 5)
return 1;
var uargs = args;
var uargs = Array.from(args);
uargs.shift();
if (args[0] == '[' && uargs[uargs.length-1] == ']')
@ -1967,7 +1967,7 @@ Options:
return 1;
break;
default:
return 2;
return 3;
}
}

View file

@ -38,6 +38,7 @@ return Object.create({
// convert a string into an argument array: 'ls /etc' -> ['ls','/etc'], supports "quoted arguments" and `command substitutions`
strToArgs:function(txt) {
var parts = [];
var wasq = false;
var sp = '';
var s = '';
var e = false;
@ -75,6 +76,7 @@ return Object.create({
}else if (txt[i] == sp) {
sp = '';
q = false;
wasq = true;
}
}else{
s += txt[i];
@ -83,7 +85,12 @@ return Object.create({
break;
case ' ':
if (!q && !c) {
parts.push(s);
if (!wasq && s[s.length-1] == ';') {
parts.push(s.substring(0,s.length-1));
parts.push(';');
}else{
parts.push(s);
}
s = '';
e = false;
q = false;
@ -92,10 +99,18 @@ return Object.create({
default:
s+=txt[i];
e = false;
wasq = false;
}
}
if (s.length > 0)
parts.push(s);
if (s.length > 0) {
if (!wasq && s[s.length-1] == ';') {
parts.push(s.substring(0,s.length-1));
parts.push(';');
}else{
parts.push(s);
}
}
return parts;
},

View file

@ -228,16 +228,55 @@ clite.commands.load('sh',function(args,env,io) {
active:null,
bufferout:null,
bufferin:null,
skipto:null,
cfg:{closout:false,closin:false,closerr:false},
last:0,
io:{},
internal:{
conditionals:[],
loops:[],
doCommand:function(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.internal.conditionals.push(cmd);
exec.run();
return;
break;
case 'then':
if (exec.last == 0) {
exec.internal.conditionals[exec.internal.conditionals.length-1].conditional = true;
}else{
exec.internal.conditionals[exec.internal.conditionals.length-1].conditional = false;
exec.skipto = 'else';
}
exec.run();
return;
break;
case 'else':
if (exec.internal.conditionals[exec.internal.conditionals.length-1].conditional != false) {
exec.skipto = 'fi';
}
exec.run();
return;
break;
case 'fi':
exec.internal.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') {
@ -403,11 +442,121 @@ clite.commands.load('sh',function(args,env,io) {
stdout:'&1',
stderr:'&2',
onlastsuccess:false,
onlastfail: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);
c = structuredClone(cmd);
}
continue;
}
if (args[i] == 'if') {
if (c.args.length > 0) {
exec.cmds.push(c);
c = structuredClone(cmd);
}
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);
c = structuredClone(cmd);
}
c.args.push(args[i]);
exec.cmds.push(c);
if (conds.length < 1) {
fault = true;
}else{
conds[conds.length-1].args.push(c);
}
c = structuredClone(cmd);
continue;
}
if (args[i] == 'else') {
if (c.args.length > 0) {
exec.cmds.push(c);
c = structuredClone(cmd);
}
c.args.push(args[i]);
exec.cmds.push(c);
if (conds.length < 1) {
fault = true;
}else{
conds[conds.length-1].args.push(c);
}
c = structuredClone(cmd);
continue;
}
if (args[i] == 'fi') {
if (c.args.length > 0) {
exec.cmds.push(c);
c = structuredClone(cmd);
}
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();
}
c = structuredClone(cmd);
continue;
}
if (args[i] == 'while') {
if (c.args.length > 0) {
exec.cmds.push(c);
c = structuredClone(cmd);
}
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);
c = structuredClone(cmd);
}
c.args.push(args[i]);
exec.cmds.push(c);
if (loops.length < 1) {
fault = true;
}else{
loops[loops.length-1].args.push(c);
}
c = structuredClone(cmd);
continue;
}
if (args[i] == 'done') {
if (c.args.length > 0) {
exec.cmds.push(c);
c = structuredClone(cmd);
}
c.args.push(args[i]);
exec.cmds.push(c);
if (loops.length < 1) {
fault = true;
}else{
loops[loops.length-1].args.push(c);
loops.pop();
}
c = structuredClone(cmd);
continue;
}
if (args[i] == '|') {
c.stdout = '|';
exec.cmds.push(c);
@ -457,10 +606,13 @@ clite.commands.load('sh',function(args,env,io) {
}
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);
var fault = false;
exec.cmds.forEach(function(c) {
exec.cmds.forEach(function(c,i) {
if (c.args.length < 1) {
fault = true;
return;
@ -468,7 +620,7 @@ clite.commands.load('sh',function(args,env,io) {
c.path = resolvePATH(c.args[0]);
});
if (fault) {
stdio.write(io.stderr,'Shell: unable to pass command\n');
stdio.write(io.stderr,'Shell: unable to parse command\n');
exec.exit();
return;
}
@ -618,7 +770,23 @@ clite.commands.load('sh',function(args,env,io) {
run:function(cb) {
if (typeof cb === 'function')
exec.callback = cb;
var c = exec.cmds.shift();
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;
@ -639,6 +807,9 @@ Options:
}
function resolvePATH(txt) {
// special case of test command
if (txt == '[')
txt = 'test';
if (typeof env.PATH === 'undefined')
env.PATH = '/bin';
var paths = env.PATH.split(':');