diff --git a/clite/commands.js b/clite/commands.js index 5ddb0ed..f23b6b2 100644 --- a/clite/commands.js +++ b/clite/commands.js @@ -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; } } diff --git a/clite/libclite.js b/clite/libclite.js index f62e1e4..090aa11 100644 --- a/clite/libclite.js +++ b/clite/libclite.js @@ -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; }, diff --git a/clite/shell.js b/clite/shell.js index 28c2540..79590ea 100644 --- a/clite/shell.js +++ b/clite/shell.js @@ -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 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(':');