mirror of
https://github.com/MightyPirates/OpenComputers.git
synced 2025-09-18 11:48:02 -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
|
||||
io.write("\n")
|
||||
end
|
||||
io.write("/", path, ":\n")
|
||||
io.write(path, ":\n")
|
||||
end
|
||||
local list, reason = fs.list(path)
|
||||
if not list then
|
||||
|
@ -4,6 +4,8 @@ local fs = require("filesystem")
|
||||
local shell = require("shell")
|
||||
local unicode = require("unicode")
|
||||
|
||||
local env = {}
|
||||
|
||||
os.execute = function(command)
|
||||
if not command then
|
||||
return type(shell) == "table"
|
||||
@ -15,6 +17,17 @@ function os.exit()
|
||||
error("terminated", 0)
|
||||
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(...)
|
||||
return fs.remove(...)
|
||||
end
|
||||
|
@ -61,65 +61,158 @@ local function findFile(name, ext)
|
||||
return false
|
||||
end
|
||||
|
||||
local function resolveAlias(program, args)
|
||||
local lastProgram = nil
|
||||
function expandVars(token)
|
||||
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
|
||||
local alias = text.tokenize(shell.getAlias(program) or program)
|
||||
if alias[1] == lastProgram then
|
||||
program = alias[1]
|
||||
if program == lastProgram then
|
||||
break
|
||||
end
|
||||
lastProgram = program
|
||||
program = alias[1]
|
||||
if args then
|
||||
for i = 2, #alias do
|
||||
table.insert(args, alias[i])
|
||||
end
|
||||
table.remove(alias, 1)
|
||||
for i = 1, #tokens do
|
||||
table.insert(alias, tokens[i])
|
||||
end
|
||||
tokens = alias
|
||||
end
|
||||
return program
|
||||
return program, tokens
|
||||
end
|
||||
|
||||
local function parseCommand(tokens)
|
||||
local program, args, input, output = tokens[1], {}, nil, nil
|
||||
if not program then
|
||||
if #tokens == 0 then
|
||||
return
|
||||
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"
|
||||
for i = 2, #tokens do
|
||||
if state == "args" then
|
||||
if tokens[i] == "<" then
|
||||
state = "input"
|
||||
elseif tokens[i] == ">" then
|
||||
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
|
||||
for i = 1, #tokens do
|
||||
local token = tokens[i]
|
||||
state = sm[state][token]
|
||||
if not sm[state] then
|
||||
return nil, state
|
||||
end
|
||||
end
|
||||
return program, args, input, output, state
|
||||
|
||||
return program, args, input, output, mode
|
||||
end
|
||||
|
||||
local function parseCommands(command)
|
||||
@ -146,6 +239,9 @@ local function parseCommands(command)
|
||||
|
||||
for i = 1, #commands do
|
||||
commands[i] = table.pack(parseCommand(commands[i]))
|
||||
if commands[i][1] == nil then
|
||||
return nil, commands[i][2]
|
||||
end
|
||||
end
|
||||
|
||||
return commands
|
||||
|
Loading…
x
Reference in New Issue
Block a user