Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- require 'org.luaj.vm2.lib.DebugLib'
- require 'org.luaj.vm2.lib.jse.LuajavaLib'
- local debug = debug
- local function duplicate(table, base)
- local t = base or { }
- for i, v in pairs(table) do
- t[i] = v
- end
- return t
- end
- local function clone(table)
- local t = { }
- local function clones(table)
- if type(table) ~= 'table' then
- return table
- end
- if not t[table] then
- t[table] = { }
- for i, v in pairs(table) do
- t[table][i] = clones(v)
- end
- end
- return t[table]
- end
- return clones(table)
- end
- local empty = { }
- local userfun = { }
- local error
- local print
- local function rvpack(...)
- local arg = {...}
- arg.n = select('#', ...)
- arg.s = 1
- return arg
- end
- local function rvunpack(t, s, n)
- return unpack(t, s or t.s, n or t.n)
- end
- local function rvshift(t, d)
- t.s = t.s + d
- return t
- end
- local function protectenv(table, force)
- local t = { }
- local getfenv = getfenv
- local setfenv = setfenv
- local select = select
- local function sub(table)
- if not t[table] then
- t[table] = true
- for i, v in pairs(table) do
- if force or userfun[v] then
- table[i] = setfenv(function(...)
- local p, err = getfenv(v)
- local f = setfenv(v, getfenv(0))
- local r = rvpack(f(...))
- if p then
- setfenv(v, p)
- end
- return rvunpack(r)
- end, empty)
- elseif type(v) == 'table' then
- sub(v)
- end
- end
- end
- end
- sub(table)
- end
- local parallels = { }
- local currentParallel = nil
- local currentProcess = nil
- local processInfo = setmetatable({}, { __mode = 'k' })
- local handles = setmetatable({}, { __mode = 'k' })
- local returnValue
- local timers = { }
- function pullEventRaw()
- local event = rvpack(coroutine.yield())
- if event[1] == 'terminate' then
- local info = processInfo[parallels[1].currentProcess]
- info.status = 'dead'
- info.parent.returnValue = rvpack('error', 'terminated')
- else
- if event[1] == 'timer' and timers[event[2]] then
- timers[event[2]]()
- timers[event[2]] = nil
- end
- return event
- end
- end
- local events = { }
- events.back = events
- local ignoreEvents = false
- local waiting = false
- local listener = { }
- local function queueEvent(event)
- local e = { value = event }
- events.back.next = e
- events.back = e
- end
- local function pullEvent(wait)
- if currentParallel.events.next then
- currentParallel.events = currentParallel.events.next
- return assert(currentParallel.events.value)
- end
- return nil
- end
- --TODO: work with parallel
- local function sleep(time)
- local timer = os.startTimer(time)
- local info = processInfo[currentProcess]
- if info.status ~= 'dead' then
- info.status = 'wait'
- info.wait = function() end
- timers[timer] = function()
- if info.status ~= 'dead' then
- info.status = 'normal'
- end
- end
- end
- end
- local function flushEvent()
- --sleep(0)
- coroutine.yield('sleep', 0)
- end
- loadfile = function(fn)
- local file = fs.open(fn, "r")
- if file then
- local func, err = loadstring(file.readAll(), fn)
- file.close()
- return func, err
- end
- return nil, "File not found"
- end
- dofile = function(fn)
- local fun, e = loadfile(fn)
- if fun then
- return fun()
- else
- error(e)
- end
- end
- function write( sText )
- local w,h = term.getSize()
- local x,y = term.getCursorPos()
- local nLinesPrinted = 0
- local function newLine()
- if y + 1 <= h then
- term.setCursorPos(1, y + 1)
- else
- term.scroll(1)
- term.setCursorPos(1, h)
- end
- x, y = term.getCursorPos()
- nLinesPrinted = nLinesPrinted + 1
- end
- -- Print the line with proper word wrapping
- while string.len(sText) > 0 do
- local whitespace = string.match( sText, "^[ \t]+" )
- if whitespace then
- -- Print whitespace
- term.write( whitespace )
- x,y = term.getCursorPos()
- sText = string.sub( sText, string.len(whitespace) + 1 )
- end
- local newline = string.match( sText, "^\n" )
- if newline then
- -- Print newlines
- newLine()
- sText = string.sub( sText, 2 )
- end
- local text = string.match( sText, "^[^ \t\n]+" )
- if text then
- sText = string.sub( sText, string.len(text) + 1 )
- if string.len(text) > w then
- -- Print a multiline word
- while string.len( text ) > 0 do
- if x > w then
- newLine()
- end
- term.write( text )
- text = string.sub( text, (w-x) + 2 )
- x,y = term.getCursorPos()
- end
- else
- -- Print a word normally
- if x + string.len(text) > w then
- newLine()
- end
- term.write( text )
- x,y = term.getCursorPos()
- end
- end
- end
- return nLinesPrinted
- end
- function print( ... )
- local nLinesPrinted = 0
- for n,v in ipairs( { ... } ) do
- nLinesPrinted = nLinesPrinted + write( tostring( v ) )
- end
- nLinesPrinted = nLinesPrinted + write( "\n" )
- return nLinesPrinted
- end
- function read( _sReplaceChar, _tHistory )
- setfenv(1, getfenv(0))
- term.setCursorBlink( true )
- local sLine = ""
- local nHistoryPos = nil
- local nPos = 0
- if _sReplaceChar then
- _sReplaceChar = string.sub( _sReplaceChar, 1, 1 )
- end
- local w, h = term.getSize()
- local sx, sy = term.getCursorPos()
- local function redraw()
- local nScroll = 0
- if sx + nPos >= w then
- nScroll = (sx + nPos) - w
- end
- term.setCursorPos( sx, sy )
- term.write( string.rep(" ", w - sx + 1) )
- term.setCursorPos( sx, sy )
- if _sReplaceChar then
- term.write( string.rep(_sReplaceChar, string.len(sLine) - nScroll) )
- else
- term.write( string.sub( sLine, nScroll + 1 ) )
- end
- term.setCursorPos( sx + nPos - nScroll, sy )
- end
- while true do
- local sEvent, param = os.pullEvent()
- if sEvent == "char" then
- sLine = string.sub( sLine, 1, nPos ) .. param .. string.sub( sLine, nPos + 1 )
- nPos = nPos + 1
- redraw()
- elseif sEvent == "key" then
- if param == 28 then
- -- Enter
- break
- elseif param == 203 then
- -- Left
- if nPos > 0 then
- nPos = nPos - 1
- redraw()
- end
- elseif param == 205 then
- -- Right
- if nPos < string.len(sLine) then
- nPos = nPos + 1
- redraw()
- end
- elseif param == 200 or param == 208 then
- -- Up or down
- if _tHistory then
- if param == 200 then
- -- Up
- if nHistoryPos == nil then
- if #_tHistory > 0 then
- nHistoryPos = #_tHistory
- end
- elseif nHistoryPos > 1 then
- nHistoryPos = nHistoryPos - 1
- end
- else
- -- Down
- if nHistoryPos == #_tHistory then
- nHistoryPos = nil
- elseif nHistoryPos ~= nil then
- nHistoryPos = nHistoryPos + 1
- end
- end
- if nHistoryPos then
- sLine = _tHistory[nHistoryPos]
- nPos = string.len( sLine )
- else
- sLine = ""
- nPos = 0
- end
- redraw()
- end
- elseif param == 14 then
- -- Backspace
- if nPos > 0 then
- sLine = string.sub( sLine, 1, nPos - 1 ) .. string.sub( sLine, nPos + 1 )
- nPos = nPos - 1
- redraw()
- end
- end
- end
- end
- term.setCursorBlink( false )
- term.setCursorPos( w + 1, sy )
- print()
- return sLine
- end
- local function split(str, sub)
- local t = { }
- local p = 1
- local q = string.find(str, sub, p, true)
- local l = string.len(sub)
- while q do
- table.insert(t, string.sub(str, p, q - 1))
- p = q + l
- q = string.find(str, sub, p, true)
- end
- end
- local tenv = {
- os = {
- version = function()
- return 'CCOS 0.2'
- end,
- computerID = os.computerID,
- run = function (env, path, ...)
- local file, err = loadfile(path)
- if file then
- local ret = rvpack(coroutine.yield('exec', loadfile(path), rvpack(...), nil, setmetatable(env, { __index = _G })))
- if ret[1] == 'error' then
- ret[1] = false
- print(ret[2])
- end
- return rvunpack(ret)
- else
- return false, err
- end
- end,
- loadAPI = function(path)
- return false, 'Premission denied'
- end,
- unloadAPI = function(name)
- return false, 'Premission denied'
- end,
- pullEvent = function()
- return coroutine.yield('pull')
- end,
- pullEventRaw = function()
- return coroutine.yield('pull')
- end,
- queueEvent = os.queueEvent,
- clock = os.clock,
- startTimer = os.startTimer,
- sleep = function(time, hold)
- coroutine.yield('sleep', time)
- if not hold then
- coroutine.yield('discard')
- end
- end,
- time = os.time,
- shutdown = function()
- coroutine.yield('shutdown')
- end,
- reboot = os.reboot,
- setAlarm = os.setAlarm,
- },
- coroutine = coroutine,
- redstone = redstone,
- term = term,
- math = math,
- table = table,
- fs = fs,
- rs = rs,
- string = string,
- sleep = function(time)
- coroutine.yield('sleep', time)
- end,
- disk = disk,
- getmetatable = getmetatable,
- unpack = unpack,
- __inext = __inext,
- _VERSION = _VERSION,
- ipairs = ipairs,
- load = load,
- print = print,
- read = read,
- write = write,
- pcall = pcall,
- assert = assert,
- tonumber = tonumber,
- rawequal = rawequal,
- loadstring = loadstring,
- loadfile = loadfile,
- dofile = dofile,
- pairs = pairs,
- collectgarbage = collectgarbage,
- xpcall = xpcall,
- error = error,
- setfenv = setfenv,
- require = function(name)
- if package.loaded[name] then
- return package.loaded[name]
- end
- for i, v in ipairs(package.loaders) do
- local f = v(name)
- if type(f) == 'function' then
- package.loaded[name] = f(name)
- if not package.loaded[name] == nil then
- package.loaded[name] = true
- end
- return package.loaded[name]
- end
- end
- error('cannot find module ' .. name)
- end,
- module = function(name, ...)
- local function do_at(fun, table, name, ...)
- if select('#', ...) ~= 0 then
- return do_at(fun, table[name], ...)
- else
- return fun(table, name)
- end
- end
- local l = split(name, '.')
- local t
- if package.loaded[name] then
- t = package.loaded[name]
- else
- t = do_at(function(t, n) return t[n] end, _G, unpack(l))
- if not t then
- package.loaded[name] = t
- do_at(function(g, n) g[n] = t end, _G, unpack(l))
- end
- end
- t._NAME = name
- t._M = t
- t._PACKAGE = string.sub(name, 1, string.len(name) - string.len(l[#l]) - 1)
- package.loaded[name] = t
- setfenv(0, t)
- for i, v in ipairs({...}) do
- v(t)
- end
- return t
- end,
- getfenv = getfenv,
- rawget = rawget,
- type = type,
- rawset = rawset,
- setmetatable = setmetatable,
- select = select,
- tostring = tostring,
- next = next,
- http = http,
- parallel = {
- create = function(f, ...)
- if select('#', ...) ~= 0 then
- return coroutine.yield('parallel', f), parallel.create(...)
- else
- return coroutine.yield('parallel', f)
- end
- end,
- waitForAny = function(...)
- coroutine.yield('wait', 1, parallel.create(...))
- end,
- waitForAll = function(...)
- coroutine.yield('wait', select('#', ...), parallel.create(...))
- end,
- },
- package = {
- cpath = '/',
- loaded = { },
- loaders = {
- function(name)
- return package.preload[name]
- end,
- function(name)
- name = string.gusb(string.gsub(name, '%.', '/'), '%%', '%%%%')
- local s = split(package.path, ';')
- for i, v in ipairs(s) do
- local fun = loadfile(string.gsub(s[i], '%?', name))
- if fun then
- return fun
- end
- end
- end,
- function(name)
- return nil
- end,
- function(name)
- return nil
- end,
- },
- path = '?;?.lua',
- preload = { },
- seeall = function(module)
- setmetatable(module, { __index = _G })
- end
- },
- }
- userfun[tenv.os.run] = true
- userfun[tenv.require] = true
- userfun[tenv.module] = true
- userfun[tenv.package.seeall] = true
- userfun[tenv.read] = true
- userfun[tenv.parallel.create] = true
- userfun[tenv.parallel.waitForAny] = true
- userfun[tenv.parallel.waitForAll] = true
- protectenv(tenv.package.loaders, true)
- --assert(userfun[nil] ~= true)
- local syscall = { }
- local function cycle()
- while parallels[1].currentProcess do
- local running = false
- for i, v in ipairs(parallels) do
- currentParallel = v
- currentProcess = v.currentProcess
- while currentProcess and processInfo[currentProcess].status == 'dead' do
- if listener[currentProcess] then
- for i, v in ipairs(listener[currentProcess]) do
- v()
- end
- end
- listener[currentProcess] = nil
- currentProcess = processInfo[currentProcess].parent
- end
- v.currentProcess = currentProcess
- if not currentProcess then
- if listener[v] then
- for i, f in ipairs(listener[v]) do
- f()
- end
- listener[v] = nil
- end
- elseif processInfo[currentProcess].status ~= 'wait' or processInfo[currentProcess].wait() then
- running = true
- returnValue = processInfo[currentProcess].returnValue
- local ret = rvpack(coroutine.resume(currentProcess, rvunpack(returnValue)))
- if not ret[1] then
- processInfo[currentProcess].status = 'dead'
- ret[1] = 'error'
- local p = processInfo[currentProcess].parent
- if p then
- processInfo[p].returnValue = ret
- else
- print(rvunpack(ret))
- end
- elseif coroutine.status(currentProcess) == 'dead' then
- processInfo[currentProcess].status = 'dead'
- ret[1] = true
- local p = processInfo[currentProcess].parent
- if p then
- processInfo[p].returnValue = ret
- end
- else
- ret[2] = ret[2] or 'pull'
- syscall[ret[2]](rvunpack(ret, 3))
- end
- end
- end
- if not running then
- queueEvent(pullEventRaw())
- end
- end
- end
- local function createProcess(file, argv, envp, eenv)
- envp = envp or duplicate(processInfo[currentProcess].environment)
- argv = argv or { }
- argv[0] = path
- argv.n = argv.n or #argv
- argv.s = argv.s or 1
- local penv = eenv or clone(tenv)
- penv._G = penv
- local co = coroutine.create(setfenv(file, penv))
- debug.setfenv(co, penv)
- debug.sethook(co, flushEvent, '', 2000)
- processInfo[co] = {
- environment = envp,
- arguments = argv,
- parent = currentProcess,
- parellel = currentParallel,
- returnValue = argv
- }
- return co
- end
- local function execf(file, argv, envp, eenv)
- local co = createProcess(file, argv, envp, eenv)
- currentParallel.currentProcess = co
- end
- local function exec(path, argv, envp, eenv)
- if type(path) == 'function' then
- return execf(path, argv, envp, eenv)
- end
- local file, err = loadfile(path)
- if file then
- return execf(file, argv, envp, eenv)
- end
- processInfo[currentProcess].returnValue = rvpack(false, err)
- end
- local function pull()
- local e = pullEvent()
- local info = processInfo[currentProcess]
- if e then
- info.returnValue = e
- elseif info.status ~= 'dead' then
- info.status = 'wait'
- e = currentParallel.events
- info.wait = function()
- if e.next then
- info.returnValue = assert(pullEvent())
- info.status = 'normal'
- return true
- end
- end
- end
- end
- local function discard()
- currentParallel.events = events.back
- end
- local function shutdown()
- os.shutdown()
- while true do
- coroutine.yield()
- end
- end
- local function parallel(func)
- local co = createProcess(func)
- local parallel = {
- currentProcess = co,
- events = currentParallel.events
- }
- local info = processInfo[co]
- info.parent = nil
- info.parallel = parallel
- table.insert(parallels, parallel)
- local v = { }
- handles[v] = parallel
- processInfo[currentProcess].returnValue = rvpack(v)
- end
- function wait(n, ...)
- for i, v in ipairs({...}) do
- if handles[v] then
- v = handles[v]
- end
- if not listener[v] then
- listener[v] = { }
- end
- if processInfo[v] and processInfo[v].status == 'dead' then
- n = n - 1
- end
- if v and v.currentProcess == nil then
- n = n - 1
- end
- table.insert(listener[v], function()
- n = n - 1
- if n <= 0 and info.status ~= 'dead' then
- info.status = 'normal'
- end
- end)
- end
- local info = processInfo[currentProcess]
- info.wait = function() end
- if info.status ~= 'dead' then
- info.status = 'wait'
- end
- end
- syscall.exec = execf
- syscall.pull = pull
- syscall.sleep = sleep
- syscall.discard = discard
- syscall.shutdown = shutdown
- syscall.parallel = parallel
- syscall.wait = wait
- local tAPIsLoading = {}
- function os.loadAPI( _sPath )
- local sName = fs.getName( _sPath )
- if tAPIsLoading[sName] == true then
- return false, "API "..sName.." is already being loaded"
- end
- tAPIsLoading[sName] = true
- local tEnv = {}
- setmetatable(tEnv, { __index = tenv })
- local fnAPI, err = loadfile( _sPath )
- if fnAPI then
- setfenv(fnAPI, tEnv)
- fnAPI()
- else
- return false, err
- end
- --_G[sName] = duplicate(tEnv)
- tenv[sName] = duplicate(tEnv, tenv[sName])
- tAPIsLoading[sName] = nil
- return true
- end
- function os.unloadAPI( _sName )
- if _sName ~= "_G" and type(_G[_sName] == "table") then
- tenv[sName] = nil
- end
- end
- -- Install the lua parts of the HTTP api (if enabled)
- if http then
- http.get = function( _url )
- local requestID = http.request( _url )
- while true do
- local event, param1, param2 = os.pullEvent()
- if event == "http_success" and param1 == _url then
- return param2
- elseif event == "http_failure" and param1 == _url then
- return nil
- end
- end
- end
- end
- -- Load APIs
- local tApis = fs.list( "rom/apis" )
- for n,sFile in ipairs( tApis ) do
- if not fs.isDir( sFile ) and sFile ~= 'parallel' then
- os.loadAPI( fs.combine( "rom/apis", sFile ) )
- end
- end
- --tenv = clone(tenv)
- protectenv(tenv)
- currentProcess = createProcess(function()
- _G.parallel.create(rednet.run)
- os.run( {}, "rom/programs/shell" )
- end, nil, { })
- local parallel = {
- currentProcess = currentProcess,
- events = events
- }
- local info = processInfo[currentProcess]
- info.parent = nil
- info.parallel = parallel
- table.insert(parallels, parallel)
- print(pcall(cycle))
- local x = returnValue
- print(rvunpack(returnValue))
- --[[
- -- Run the shell
- local ok, err = pcall( function()
- parallel.waitForAny(
- function()
- rednet.run()
- end,
- function()
- os.run( {}, "rom/programs/shell" )
- end
- )
- end )
- if not ok then
- print( err )
- end
- ]]
- -- If the shell didn't shutdown the computer,
- -- it probably errored, so let the user read it.
- pcall( function()
- term.setCursorBlink( false )
- print( "Press any key to continue" )
- repeat
- local event = pullEventRaw()
- until event[1] == "key"
- end )
- os.shutdown() -- Just in case
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement