mirror of
https://github.com/MightyPirates/OpenComputers.git
synced 2025-09-19 04:06:43 -04:00
added os.getenv and os.setenv; cleaned up and patched redirect parsing; added variable expansion and groundwork for further stuff to shell (contributed by @Wobbo)
This commit is contained in:
parent
0c37b69422
commit
183f00b398
@ -13,7 +13,7 @@ for i = 1, #dirs do
|
|||||||
if i > 1 then
|
if i > 1 then
|
||||||
io.write("\n")
|
io.write("\n")
|
||||||
end
|
end
|
||||||
io.write("/", path, ":\n")
|
io.write(path, ":\n")
|
||||||
end
|
end
|
||||||
local list, reason = fs.list(path)
|
local list, reason = fs.list(path)
|
||||||
if not list then
|
if not list then
|
||||||
|
@ -4,6 +4,8 @@ local fs = require("filesystem")
|
|||||||
local shell = require("shell")
|
local shell = require("shell")
|
||||||
local unicode = require("unicode")
|
local unicode = require("unicode")
|
||||||
|
|
||||||
|
local env = {}
|
||||||
|
|
||||||
os.execute = function(command)
|
os.execute = function(command)
|
||||||
if not command then
|
if not command then
|
||||||
return type(shell) == "table"
|
return type(shell) == "table"
|
||||||
@ -15,6 +17,17 @@ function os.exit()
|
|||||||
error("terminated", 0)
|
error("terminated", 0)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function os.getenv(varname)
|
||||||
|
return env[varname]
|
||||||
|
end
|
||||||
|
|
||||||
|
function os.setenv(varname, value)
|
||||||
|
checkArg(1, varname, "string")
|
||||||
|
checkArg(2, value, "string", "nil")
|
||||||
|
env[varname] = value
|
||||||
|
return env[varname]
|
||||||
|
end
|
||||||
|
|
||||||
function os.remove(...)
|
function os.remove(...)
|
||||||
return fs.remove(...)
|
return fs.remove(...)
|
||||||
end
|
end
|
||||||
|
@ -61,65 +61,158 @@ local function findFile(name, ext)
|
|||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
local function resolveAlias(program, args)
|
function expandVars(token)
|
||||||
local lastProgram = nil
|
local name = nil
|
||||||
|
local special = false
|
||||||
|
local ignore = false
|
||||||
|
local ignoreChar =''
|
||||||
|
local escaped = false
|
||||||
|
local lastEnd = 1
|
||||||
|
local doubleQuote = false
|
||||||
|
local singleQuote = false
|
||||||
|
local endToken = {}
|
||||||
|
for i = 1, unicode.len(token) do
|
||||||
|
local char = unicode.sub(token, i, i)
|
||||||
|
if escaped then
|
||||||
|
if name then
|
||||||
|
table.insert(name, char)
|
||||||
|
end
|
||||||
|
escaped = false
|
||||||
|
elseif char == '\\' then
|
||||||
|
escaped = not escaped
|
||||||
|
table.insert(endToken, unicode.sub(token, lastEnd, i-1))
|
||||||
|
lastEnd = i+1
|
||||||
|
elseif char == '"' and not singleQuote then
|
||||||
|
doubleQuote = not doubleQuote
|
||||||
|
table.insert(endToken, unicode.sub(token, lastEnd, i-1))
|
||||||
|
lastEnd = i+1
|
||||||
|
elseif char == "'" and not doubleQuote then
|
||||||
|
singleQuote = not singleQuote
|
||||||
|
table.insert(endToken, unicode.sub(token, lastEnd, i-1))
|
||||||
|
lastEnd = i+1
|
||||||
|
elseif char == "$" and not doubleQuote and not singleQuote then
|
||||||
|
if name then
|
||||||
|
ignore = true
|
||||||
|
else
|
||||||
|
name = {}
|
||||||
|
table.insert(endToken, unicode.sub(token, lastEnd, i-1))
|
||||||
|
end
|
||||||
|
elseif char == '{' and #name == 0 then
|
||||||
|
if ignore and ignoreChar == '' then
|
||||||
|
ignoreChar = '}'
|
||||||
|
else
|
||||||
|
special = true
|
||||||
|
end
|
||||||
|
elseif char == '(' and ignoreChar == '' then
|
||||||
|
ignoreChar = ')'
|
||||||
|
elseif char == '`' and special then
|
||||||
|
ignore = true
|
||||||
|
ignoreChar = '`'
|
||||||
|
elseif char == '}' and not ignore and not doubleQuote and not singleQuote then
|
||||||
|
table.insert(endToken, os.getenv(table.concat(name)))
|
||||||
|
name = nil
|
||||||
|
lastEnd = i+1
|
||||||
|
elseif char == '"' and not singleQuote then
|
||||||
|
doubleQuote = not doubleQuote
|
||||||
|
elseif char == "'" and not doubleQuote then
|
||||||
|
singleQuote = not singleQuote
|
||||||
|
elseif name and (char:match("[%a%d_]") or special) then
|
||||||
|
if char:match("%d") and #name == 0 then
|
||||||
|
error "Identifiers can't start with a digit!"
|
||||||
|
end
|
||||||
|
table.insert(name, char)
|
||||||
|
elseif char == ignoreChar and ignore then
|
||||||
|
ignore = false
|
||||||
|
ignoreChar = ''
|
||||||
|
elseif name then -- We are done with gathering the name
|
||||||
|
table.insert(endToken, os.getenv(table.concat(name)))
|
||||||
|
name = nil
|
||||||
|
lastEnd = i
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if name then
|
||||||
|
table.insert(endToken, os.getenv(table.concat(name)))
|
||||||
|
name = nil
|
||||||
|
else
|
||||||
|
table.insert(endToken, unicode.sub(token, lastEnd, -1))
|
||||||
|
end
|
||||||
|
return table.concat(endToken)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function resolveAlias(tokens)
|
||||||
|
local program, lastProgram = tokens[1], nil
|
||||||
|
table.remove(tokens, 1)
|
||||||
while true do
|
while true do
|
||||||
local alias = text.tokenize(shell.getAlias(program) or program)
|
local alias = text.tokenize(shell.getAlias(program) or program)
|
||||||
if alias[1] == lastProgram then
|
program = alias[1]
|
||||||
|
if program == lastProgram then
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
lastProgram = program
|
lastProgram = program
|
||||||
program = alias[1]
|
table.remove(alias, 1)
|
||||||
if args then
|
for i = 1, #tokens do
|
||||||
for i = 2, #alias do
|
table.insert(alias, tokens[i])
|
||||||
table.insert(args, alias[i])
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
tokens = alias
|
||||||
end
|
end
|
||||||
return program
|
return program, tokens
|
||||||
end
|
end
|
||||||
|
|
||||||
local function parseCommand(tokens)
|
local function parseCommand(tokens)
|
||||||
local program, args, input, output = tokens[1], {}, nil, nil
|
if #tokens == 0 then
|
||||||
if not program then
|
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
program = resolveAlias(program, args)
|
-- Variable expansion for all command parts.
|
||||||
|
for i = 1, #tokens do
|
||||||
|
tokens[i] = expandVars(tokens[i])
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Resolve alias for command.
|
||||||
|
local program, args = resolveAlias(tokens)
|
||||||
|
|
||||||
|
-- Find redirects.
|
||||||
|
local input, output, mode = nil, nil, "write"
|
||||||
|
tokens = args
|
||||||
|
args = {}
|
||||||
|
local function smt(call) -- state metatable factory
|
||||||
|
local function index(_, token)
|
||||||
|
if token == "<" or token == ">" or token == ">>" then
|
||||||
|
return "parse error near " .. token
|
||||||
|
end
|
||||||
|
call(token)
|
||||||
|
return "args" -- default, return to normal arg parsing
|
||||||
|
end
|
||||||
|
return {__index=index}
|
||||||
|
end
|
||||||
|
local sm = { -- state machine for redirect parsing
|
||||||
|
args = setmetatable({["<"]="input", [">"]="output", [">>"]="append"},
|
||||||
|
smt(function(token)
|
||||||
|
table.insert(args, token)
|
||||||
|
end)),
|
||||||
|
input = setmetatable({}, smt(function(token)
|
||||||
|
input = token
|
||||||
|
end)),
|
||||||
|
output = setmetatable({}, smt(function(token)
|
||||||
|
output = token
|
||||||
|
mode = "write"
|
||||||
|
end)),
|
||||||
|
append = setmetatable({}, smt(function(token)
|
||||||
|
output = token
|
||||||
|
mode = "append"
|
||||||
|
end))
|
||||||
|
}
|
||||||
|
-- Run state machine over tokens.
|
||||||
local state = "args"
|
local state = "args"
|
||||||
for i = 2, #tokens do
|
for i = 1, #tokens do
|
||||||
if state == "args" then
|
local token = tokens[i]
|
||||||
if tokens[i] == "<" then
|
state = sm[state][token]
|
||||||
state = "input"
|
if not sm[state] then
|
||||||
elseif tokens[i] == ">" then
|
return nil, state
|
||||||
state = "output"
|
|
||||||
elseif tokens[i] == ">>" then
|
|
||||||
state = "append"
|
|
||||||
else
|
|
||||||
table.insert(args, tokens[i])
|
|
||||||
end
|
|
||||||
elseif state == "input" then
|
|
||||||
if tokens[i] == ">" then
|
|
||||||
if not input then
|
|
||||||
return nil, "parse error near '>'"
|
|
||||||
end
|
|
||||||
state = "output"
|
|
||||||
elseif tokens[i] == ">>" then
|
|
||||||
if not input then
|
|
||||||
return nil, "parse error near '>>'"
|
|
||||||
end
|
|
||||||
state = "append"
|
|
||||||
elseif not input then
|
|
||||||
input = tokens[i]
|
|
||||||
end
|
|
||||||
elseif state == "output" or state == "append" then
|
|
||||||
if not output then
|
|
||||||
output = tokens[i]
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return program, args, input, output, state
|
|
||||||
|
return program, args, input, output, mode
|
||||||
end
|
end
|
||||||
|
|
||||||
local function parseCommands(command)
|
local function parseCommands(command)
|
||||||
@ -146,6 +239,9 @@ local function parseCommands(command)
|
|||||||
|
|
||||||
for i = 1, #commands do
|
for i = 1, #commands do
|
||||||
commands[i] = table.pack(parseCommand(commands[i]))
|
commands[i] = table.pack(parseCommand(commands[i]))
|
||||||
|
if commands[i][1] == nil then
|
||||||
|
return nil, commands[i][2]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return commands
|
return commands
|
||||||
|
Loading…
x
Reference in New Issue
Block a user