Permalink
Cannot retrieve contributors at this time
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
cclite/src/api.lua
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
1488 lines (1412 sloc)
42.3 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| local real_error = error | |
| local function error(str,level) | |
| if level == nil then level = 1 end | |
| if type(level) ~= "number" then | |
| real_error("bad argument: int expected, got " .. type(level),2) | |
| end | |
| if level <= 0 then | |
| level = -2 | |
| end | |
| str = str == nil and "" or tostring(str) | |
| local info = debug.getinfo(level+1) | |
| if info ~= nil then | |
| str = (info.source == "=[C]" and info.name or info.short_src .. ":" .. info.currentline) .. ": " .. str | |
| end | |
| real_error(str,-1) | |
| end | |
| -- HELPER FUNCTIONS | |
| local function lines(str) | |
| str=str:gsub("\r\n","\n"):gsub("\r","\n"):gsub("\n$","").."\n" | |
| local out={} | |
| for line in str:gmatch("([^\n]*)\n") do | |
| table.insert(out,line) | |
| end | |
| return out | |
| end | |
| -- HELPER CLASSES/HANDLES | |
| local HTTPHandle | |
| if _conf.enableAPI_http then | |
| function HTTPHandle(contents, status) | |
| local closed = false | |
| local lineIndex = 1 | |
| local handle | |
| handle = { | |
| close = function() | |
| closed = true | |
| end, | |
| readLine = function() | |
| if closed then return end | |
| local str = contents[lineIndex] | |
| lineIndex = lineIndex + 1 | |
| return str | |
| end, | |
| readAll = function() | |
| if closed then return end | |
| if lineIndex == 1 then | |
| lineIndex = #contents + 1 | |
| return table.concat(contents, '\n') | |
| else | |
| local tData = {} | |
| local data = handle.readLine() | |
| while data ~= nil do | |
| table.insert(tData, data) | |
| data = handle.readLine() | |
| end | |
| return table.concat(tData, '\n') | |
| end | |
| end, | |
| getResponseCode = function() | |
| return status | |
| end | |
| } | |
| return handle | |
| end | |
| end | |
| -- Needed for term.write, (file).write, and (file).writeLine | |
| -- This serialzier is bad, it is supposed to be bad. Don't use it. | |
| local function serializeImpl(t, tTracking) | |
| local sType = type(t) | |
| if sType == "table" then | |
| if tTracking[t] ~= nil then | |
| return nil | |
| end | |
| tTracking[t] = true | |
| local result = "{" | |
| for k,v in pairs(t) do | |
| local cache1 = serializeImpl(k, tTracking) | |
| local cache2 = serializeImpl(v, tTracking) | |
| if cache1 ~= nil and cache2 ~= nil then | |
| result = result..cache1.."="..cache2..", " | |
| end | |
| end | |
| if result:sub(-2,-1) == ", " then result = result:sub(1,-3) end | |
| result = result.."}" | |
| return result | |
| elseif sType == "string" then | |
| return t | |
| elseif sType == "number" then | |
| if t == math.huge then | |
| return "Infinity" | |
| elseif t == -math.huge then | |
| return "-Infinity" | |
| elseif t ~= t then | |
| return "NaN" | |
| else | |
| return tostring(t):gsub("^[^e.]+%f[^0-9.]","%1.0"):gsub("e%+","e"):upper() | |
| end | |
| elseif sType == "boolean" then | |
| return tostring(t) | |
| else | |
| return nil | |
| end | |
| end | |
| local function serialize(t) | |
| local tTracking = {} | |
| return serializeImpl(t, tTracking) or "" | |
| end | |
| local function string_trim(s) | |
| local from = s:match"^%s*()" | |
| return from > #s and "" or s:match(".*%S", from) | |
| end | |
| local utf8=require("utf8") | |
| local function cleanUTF8(str) | |
| -- TODO: Not accurate, but gets the job done. | |
| while true do | |
| local ok, bad = utf8.len(str) | |
| if ok then break end | |
| str = string.sub(str, 1, bad-1) .. "?" .. string.sub(str, bad+1) | |
| end | |
| return (str:gsub("[\xC4-\xF4][\x80-\xBF]*", "?"):gsub("[\xC2-\xC3][\x80-\xBF]*", function(a) return string.char(utf8.codepoint(a)) end)) | |
| end | |
| local function FileReadHandle(path) | |
| if not vfs.exists(path) then | |
| return nil | |
| end | |
| local contents = {} | |
| for line in vfs.lines(path) do | |
| table.insert(contents, cleanUTF8(line)) | |
| end | |
| local closed = false | |
| local lineIndex = 1 | |
| local handle | |
| handle = { | |
| close = function() | |
| closed = true | |
| end, | |
| readLine = function() | |
| if closed then return end | |
| local str = contents[lineIndex] | |
| lineIndex = lineIndex + 1 | |
| return str | |
| end, | |
| readAll = function() | |
| if closed then return end | |
| if lineIndex == 1 then | |
| lineIndex = #contents + 1 | |
| return table.concat(contents, '\n') | |
| else | |
| local tData = {} | |
| local data = handle.readLine() | |
| while data ~= nil do | |
| table.insert(tData, data) | |
| data = handle.readLine() | |
| end | |
| return table.concat(tData, '\n') | |
| end | |
| end | |
| } | |
| return handle | |
| end | |
| local function FileBinaryReadHandle(path) | |
| if not vfs.exists(path) then | |
| return nil | |
| end | |
| local closed = false | |
| local File = vfs.newFile(path, "r") | |
| if File == nil then return end | |
| local handle = { | |
| close = function() | |
| closed = true | |
| File:close() | |
| end, | |
| read = function() | |
| if closed or File:eof() then return end | |
| return File:read(1):byte() | |
| end | |
| } | |
| return handle | |
| end | |
| local function convUTF8(data) | |
| return (data:gsub("[\128-\255]", function(a) | |
| local byte=a:byte() | |
| if byte >= 128 and byte < 192 then | |
| return "\xC2"..a | |
| else | |
| return string.char(0xC3, byte-64) | |
| end | |
| end)) | |
| end | |
| local function FileWriteHandle(path, append) | |
| local closed = false | |
| if path:find("/",nil,true) then | |
| vfs.createDirectory(path:match("(.*)/")) | |
| end | |
| local File = vfs.newFile(path, append and "a" or "w") | |
| if File == nil then return end | |
| local handle = { | |
| close = function() | |
| closed = true | |
| File:close() | |
| end, | |
| writeLine = function(data) | |
| if closed then error("Stream closed",2) end | |
| File:write(convUTF8(serialize(data)) .. (_conf.useCRLF and "\r\n" or "\n")) | |
| end, | |
| write = function(data) | |
| if closed then error("Stream closed",2) end | |
| File:write(convUTF8(serialize(data))) | |
| end, | |
| flush = function() | |
| File:flush() | |
| end | |
| } | |
| return handle | |
| end | |
| local function FileBinaryWriteHandle(path, append) | |
| local closed = false | |
| if path:find("/",nil,true) then | |
| vfs.createDirectory(path:match("(.*)/")) | |
| end | |
| local File = vfs.newFile(path, append and "a" or "w") | |
| if File == nil then return end | |
| local handle = { | |
| close = function() | |
| closed = true | |
| File:close() | |
| end, | |
| write = function(data) | |
| if closed then return end | |
| if type(data) ~= "number" then return end | |
| while data < 0 do | |
| data = data + 256 | |
| end | |
| File:write(string.char(data % 256)) | |
| end, | |
| flush = function() | |
| File:flush() | |
| end | |
| } | |
| return handle | |
| end | |
| local ffi=require("ffi") | |
| api = {} | |
| local _tostring_DB = {} | |
| local function addToDB(entry) | |
| for k,v in pairs(entry) do | |
| if tostring(v):find("function: builtin#") ~= nil then | |
| _tostring_DB[v] = k | |
| end | |
| end | |
| end | |
| addToDB(_G) | |
| addToDB(math) | |
| addToDB(string) | |
| addToDB(table) | |
| addToDB(coroutine) | |
| function api.tostring(...) | |
| if select("#",...) == 0 then error("bad argument #1: value expected",2) end | |
| local thing = ... | |
| local fix | |
| if thing == nil then | |
| return "nil" | |
| elseif type(thing) == "number" then | |
| if thing == 1/0 or thing == -1/0 or thing ~= thing or (math.floor(thing) == thing and thing < 2^63 and thing >= -2^63) then | |
| fix = string.format("%.0f",thing) | |
| else | |
| fix = string.format("%.8G",thing):gsub("E%+","E") | |
| end | |
| return fix | |
| elseif type(thing) == "table" then | |
| fix = tostring(thing):gsub("table: 0x","table: ") | |
| return fix | |
| elseif _tostring_DB[thing] ~= nil then | |
| return _tostring_DB[thing] | |
| elseif type(thing) == "function" then | |
| fix = tostring(thing):gsub("function: 0x","function: ") | |
| return fix | |
| else | |
| return tostring(thing) | |
| end | |
| end | |
| function api.tonumber(...) | |
| local str, base = ... | |
| if select("#",...) < 1 then | |
| error("bad argument #1: value expected",2) | |
| end | |
| if base == nil then base = 10 end | |
| if (type(base) ~= "number" and type(base) ~= "string") or (type(base) == "string" and tonumber(base) == nil) then | |
| if type(base) == "string" then | |
| error("bad argument: number expected, got string",2) | |
| end | |
| error("bad argument: int expected, got " .. type(base),2) | |
| end | |
| base = math.floor(tonumber(base)) | |
| if base < 2 or base >= 37 then | |
| error("bad argument #2: base out of range",2) | |
| end | |
| if base ~= 10 then | |
| if type(str) ~= "number" and type(str) ~= "string" then | |
| error("bad argument: string expected, got " .. type(str),2) | |
| else | |
| str = string_trim(tostring(str)) | |
| end | |
| end | |
| -- Fix some strings. | |
| if type(str) == "string" and base >= 11 then | |
| str = str:gsub("%[","4"):gsub("\\","5"):gsub("]","6"):gsub("%^","7"):gsub("_","8"):gsub("`","9") | |
| end | |
| if base ~= 10 and str:sub(1,1) == "-" then | |
| local tmpnum = tonumber(str:sub(2),base) | |
| return (tmpnum ~= nil and str:sub(2,2) ~= "-") and -tmpnum or nil | |
| else | |
| return tonumber(str,base) | |
| end | |
| end | |
| function api.getfenv(level) | |
| if level == nil then level = 1 end | |
| if type(level) ~= "function" and type(level) ~= "number" then | |
| error("bad argument: " .. (type(level) == "string" and "number" or "int") .. " expected, got " .. type(level),2) | |
| end | |
| local stat,env | |
| if type(level) == "function" then | |
| env = getfenv(level) | |
| else | |
| if level < 0 then | |
| error("bad argument #1: level must be non-negative",2) | |
| end | |
| stat,env = pcall(getfenv,level + 2) | |
| if not stat then | |
| error("bad argument #1: invalid level",2) | |
| end | |
| end | |
| if env.love == love then | |
| return api.env | |
| end | |
| return env | |
| end | |
| function api.loadstring(str, source) | |
| if source == nil then source = "string" end | |
| if type(str) ~= "string" and type(str) ~= "number" then error("bad argument: string expected, got " .. type(str),2) end | |
| if type(source) ~= "string" and type(source) ~= "number" then error("bad argument: String expected, got " .. type(str),2) end | |
| local source2 = tostring(source) | |
| local sSS = source2:sub(1,1) | |
| if sSS == "@" or sSS == "=" then | |
| source2 = source2:sub(2) | |
| end | |
| local f, err = loadstring(str, "@" .. source2) | |
| if f == nil then | |
| -- Get the normal error message | |
| local _, err = loadstring(str, source) | |
| local info = debug.getinfo(2) | |
| if info ~= nil then | |
| err = (info.source == "=[C]" and info.name or info.short_src .. ":" .. info.currentline) .. ": " .. err | |
| end | |
| return f, err | |
| end | |
| jit.off(f) -- Required for "Too long without yielding" | |
| setfenv(f, api.env) | |
| return f, err | |
| end | |
| api.inext = (ipairs({})) -- Grab inext from ipairs | |
| api.term = {} | |
| local function validateColor(color,def) | |
| if color >= 48 and color <= 57 then | |
| return color - 48 | |
| elseif color >= 97 and color <= 102 then | |
| return color - 87 | |
| end | |
| return def | |
| end | |
| function api.term.blit(text,fg,bg) | |
| if type(text) ~= "string" or type(fg) ~= "string" or type(bg) ~= "string" then | |
| error("Expected string, string, string",2) | |
| end | |
| if #text ~= #fg or #text ~= #bg then | |
| error("Arguments must be the same length",2) | |
| end | |
| if Computer.state.cursorY > _conf.terminal_height or Computer.state.cursorY < 1 or Computer.state.cursorX > _conf.terminal_width then | |
| Computer.state.cursorX = Computer.state.cursorX + #text | |
| return | |
| end | |
| for i = 1, #text do | |
| local char = text:sub(i, i) | |
| if Computer.state.cursorX + i - 1 >= 1 then | |
| if Computer.state.cursorX + i - 1 > _conf.terminal_width then | |
| break | |
| end | |
| Screen.textB[Computer.state.cursorY][Computer.state.cursorX + i - 1] = char | |
| Screen.textColourB[Computer.state.cursorY][Computer.state.cursorX + i - 1] = 2^validateColor(fg:byte(i,i),0) | |
| Screen.backgroundColourB[Computer.state.cursorY][Computer.state.cursorX + i - 1] = 2^validateColor(bg:byte(i,i),15) | |
| end | |
| end | |
| Computer.state.cursorX = Computer.state.cursorX + #text | |
| Screen.dirty = true | |
| end | |
| function api.term.clear() | |
| for y = 1, _conf.terminal_height do | |
| for x = 1, _conf.terminal_width do | |
| Screen.textB[y][x] = " " | |
| Screen.backgroundColourB[y][x] = Computer.state.bg | |
| Screen.textColourB[y][x] = 1 | |
| end | |
| end | |
| Screen.dirty = true | |
| end | |
| function api.term.clearLine() | |
| if Computer.state.cursorY > _conf.terminal_height or Computer.state.cursorY < 1 then | |
| return | |
| end | |
| for x = 1, _conf.terminal_width do | |
| Screen.textB[Computer.state.cursorY][x] = " " | |
| Screen.backgroundColourB[Computer.state.cursorY][x] = Computer.state.bg | |
| Screen.textColourB[Computer.state.cursorY][x] = 1 | |
| end | |
| Screen.dirty = true | |
| end | |
| function api.term.getSize() | |
| return _conf.terminal_width, _conf.terminal_height | |
| end | |
| function api.term.getCursorPos() | |
| return Computer.state.cursorX, Computer.state.cursorY | |
| end | |
| function api.term.setCursorPos(...) | |
| local x, y = ... | |
| if type(x) ~= "number" or type(y) ~= "number" or select("#",...) ~= 2 then error("Expected number, number",2) end | |
| Computer.state.cursorX = math.floor(x) | |
| Computer.state.cursorY = math.floor(y) | |
| Screen.dirty = true | |
| end | |
| function api.term.write(text) | |
| text = serialize(text) | |
| if Computer.state.cursorY > _conf.terminal_height or Computer.state.cursorY < 1 or Computer.state.cursorX > _conf.terminal_width then | |
| Computer.state.cursorX = Computer.state.cursorX + #text | |
| return | |
| end | |
| for i = 1, #text do | |
| local char = text:sub(i, i) | |
| if Computer.state.cursorX + i - 1 >= 1 then | |
| if Computer.state.cursorX + i - 1 > _conf.terminal_width then | |
| break | |
| end | |
| Screen.textB[Computer.state.cursorY][Computer.state.cursorX + i - 1] = char | |
| Screen.textColourB[Computer.state.cursorY][Computer.state.cursorX + i - 1] = Computer.state.fg | |
| Screen.backgroundColourB[Computer.state.cursorY][Computer.state.cursorX + i - 1] = Computer.state.bg | |
| end | |
| end | |
| Computer.state.cursorX = Computer.state.cursorX + #text | |
| Screen.dirty = true | |
| end | |
| function api.term.getTextColor() | |
| return Computer.state.fg | |
| end | |
| function api.term.setTextColor(...) | |
| local num = ... | |
| if type(num) ~= "number" or select("#",...) ~= 1 then error("Expected number",2) end | |
| if num < 1 or num >= 65536 or num ~= num then | |
| error("Colour out of range",2) | |
| end | |
| num = 2^math.floor(math.log(num)/math.log(2)) | |
| Computer.state.fg = num | |
| Screen.dirty = true | |
| end | |
| function api.term.getBackgroundColor() | |
| return Computer.state.bg | |
| end | |
| function api.term.setBackgroundColor(...) | |
| local num = ... | |
| if type(num) ~= "number" or select("#",...) ~= 1 then error("Expected number",2) end | |
| if num < 1 or num >= 65536 or num ~= num then | |
| error("Colour out of range",2) | |
| end | |
| num = 2^math.floor(math.log(num)/math.log(2)) | |
| Computer.state.bg = num | |
| end | |
| function api.term.isColor() | |
| return true | |
| end | |
| function api.term.setCursorBlink(...) | |
| local bool = ... | |
| if type(bool) ~= "boolean" or select("#",...) ~= 1 then error("Expected boolean",2) end | |
| Computer.state.blink = bool | |
| Screen.dirty = true | |
| end | |
| function api.term.scroll(...) | |
| local n = ... | |
| if type(n) ~= "number" or select("#",...) ~= 1 then error("Expected number",2) end | |
| local textBuffer = {} | |
| local backgroundColourBuffer = {} | |
| local textColourBuffer = {} | |
| for y = 1, _conf.terminal_height do | |
| if y - n > 0 and y - n <= _conf.terminal_height then | |
| textBuffer[y - n] = {} | |
| backgroundColourBuffer[y - n] = {} | |
| textColourBuffer[y - n] = {} | |
| for x = 1, _conf.terminal_width do | |
| textBuffer[y - n][x] = Screen.textB[y][x] | |
| backgroundColourBuffer[y - n][x] = Screen.backgroundColourB[y][x] | |
| textColourBuffer[y - n][x] = Screen.textColourB[y][x] | |
| end | |
| end | |
| end | |
| for y = 1, _conf.terminal_height do | |
| if textBuffer[y] ~= nil then | |
| for x = 1, _conf.terminal_width do | |
| Screen.textB[y][x] = textBuffer[y][x] | |
| Screen.backgroundColourB[y][x] = backgroundColourBuffer[y][x] | |
| Screen.textColourB[y][x] = textColourBuffer[y][x] | |
| end | |
| else | |
| for x = 1, _conf.terminal_width do | |
| Screen.textB[y][x] = " " | |
| Screen.backgroundColourB[y][x] = Computer.state.bg | |
| Screen.textColourB[y][x] = 1 -- Don't need to bother setting text color | |
| end | |
| end | |
| end | |
| Screen.dirty = true | |
| end | |
| function tablecopy(orig) | |
| local orig_type = type(orig) | |
| local copy | |
| if orig_type == 'table' then | |
| copy = {} | |
| for orig_key, orig_value in pairs(orig) do | |
| copy[orig_key] = orig_value | |
| end | |
| else | |
| copy = orig | |
| end | |
| return copy | |
| end | |
| api.cclite = {} | |
| if _conf.enableAPI_cclite then | |
| function api.cclite.peripheralAttach(sSide, sType) | |
| if type(sSide) ~= "string" or type(sType) ~= "string" then | |
| error("Expected string, string",2) | |
| end | |
| if not peripheral.base[sType] then | |
| error("No virtual peripheral of type " .. sType,2) | |
| end | |
| if Computer.state.peripherals[sSide] then | |
| error("Peripheral already attached to " .. sSide,2) | |
| end | |
| Computer.state.peripherals[sSide] = peripheral.base[sType](sSide) | |
| if Computer.state.peripherals[sSide] ~= nil then | |
| local methods = Computer.state.peripherals[sSide].getMethods() | |
| Computer.state.peripherals[sSide].cache = {} | |
| for i = 1,#methods do | |
| Computer.state.peripherals[sSide].cache[methods[i]] = true | |
| end | |
| local ccliteMethods = Computer.state.peripherals[sSide].ccliteGetMethods() | |
| Computer.state.peripherals[sSide].ccliteCache = {} | |
| for i = 1,#ccliteMethods do | |
| Computer.state.peripherals[sSide].ccliteCache[ccliteMethods[i]] = true | |
| end | |
| table.insert(Computer.eventQueue, {"peripheral",sSide}) | |
| else | |
| error("No peripheral added",2) | |
| end | |
| end | |
| function api.cclite.peripheralDetach(sSide) | |
| if type(sSide) ~= "string" then error("Expected string",2) end | |
| if not Computer.state.peripherals[sSide] then | |
| error("No peripheral attached to " .. sSide,2) | |
| end | |
| Computer.state.peripherals[sSide] = nil | |
| table.insert(Computer.eventQueue, {"peripheral_detach",sSide}) | |
| end | |
| function api.cclite.getMethods(sSide) | |
| if type(sSide) ~= "string" then error("Expected string",2) end | |
| if Computer.state.peripherals[sSide] then return Computer.state.peripherals[sSide].ccliteGetMethods() end | |
| return | |
| end | |
| function api.cclite.call(sSide, sMethod, ...) | |
| if type(sSide) ~= "string" then error("Expected string",2) end | |
| if type(sMethod) ~= "string" then error("Expected string, string",2) end | |
| if not Computer.state.peripherals[sSide] then error("No peripheral attached",2) end | |
| return Computer.state.peripherals[sSide].ccliteCall(sMethod, ...) | |
| end | |
| function api.cclite.message(sMessage) | |
| if type(sMessage) ~= "string" then error("Expected string",2) end | |
| Screen:message(sMessage) | |
| end | |
| end | |
| if _conf.enableAPI_http then | |
| local https_alert=false | |
| api.http = {} | |
| function api.http.checkURL(sUrl) | |
| if type(sUrl) ~= "string" then | |
| error("Expected string",2) | |
| end | |
| local goodUrl = string_trim(sUrl) | |
| if goodUrl:sub(1,4) == "ftp:" or goodUrl:sub(1,5) == "file:" or goodUrl:sub(1,7) == "mailto:" then | |
| return false, "URL not http" | |
| end | |
| if goodUrl:sub(1,5) ~= "http:" and goodUrl:sub(1,6) ~= "https:" then | |
| return false, "URL malformed" | |
| end | |
| return true | |
| end | |
| function api.http.request(sUrl, sPostbody, tHeaders) | |
| if type(sUrl) ~= "string" then | |
| error("Expected string",2) | |
| end | |
| local goodUrl = string_trim(sUrl) | |
| if goodUrl:sub(1,4) == "ftp:" or goodUrl:sub(1,5) == "file:" or goodUrl:sub(1,7) == "mailto:" then | |
| return false, "URL not http" | |
| end | |
| if goodUrl:sub(1,5) ~= "http:" and goodUrl:sub(1,6) ~= "https:" then | |
| return false, "URL malformed" | |
| end | |
| if goodUrl:sub(1,6) == "https:" and not _conf.useLuaSec then | |
| if not https_alert then | |
| https_alert=true | |
| Screen:message("Warning: No HTTPS support enabled, falling back to HTTP") | |
| end | |
| print("Warning: Attempted to load page \"" .. goodUrl .. "\" without HTTPS support enabled") | |
| end | |
| if type(sPostbody) ~= "string" then | |
| sPostbody = nil | |
| end | |
| local http = HttpRequest.new() | |
| local method = sPostbody and "POST" or "GET" | |
| http.open(method, goodUrl, true) | |
| http.setRequestHeader("Accept-Charset", "UTF-8"); | |
| if method == "POST" then | |
| http.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8") | |
| http.setRequestHeader("Content-Encoding", "UTF-8"); | |
| http.setRequestHeader("Content-Length", sPostbody:len()) | |
| end | |
| if type(tHeaders) == "table" then | |
| for k, v in pairs(tHeaders) do | |
| if type(k) == "string" and type(v) == "string" then | |
| local lk=string.lower(k) | |
| if lk ~= "host" and lk ~= "connection" and lk ~= "content-length" then | |
| http.setRequestHeader(k, v) | |
| end | |
| end | |
| end | |
| end | |
| http.onReadyStateChange = function() | |
| if http.status == 200 then | |
| local handle = HTTPHandle(lines(http.responseText), http.status) | |
| table.insert(Computer.eventQueue, {"http_success", sUrl, handle}) | |
| else | |
| table.insert(Computer.eventQueue, {"http_failure", sUrl, "Could not connect"}) | |
| end | |
| end | |
| http.send(sPostbody) | |
| return true | |
| end | |
| end | |
| api.os = {} | |
| function api.os.clock() | |
| return tonumber(string.format("%0.2f",math.floor(love.timer.getTime()*20)/20 - Computer.state.startTime)) | |
| end | |
| function api.os.time() | |
| return math.floor(((love.timer.getTime()-Computer.state.startTime)*0.02)%24*1000)/1000 | |
| end | |
| function api.os.day() | |
| return math.floor((love.timer.getTime()-Computer.state.startTime)/1200) | |
| end | |
| function api.os.setComputerLabel(label) | |
| if type(label) == "function" then label = nil end | |
| if type(label) ~= "string" and type(label) ~= "nil" then error("Expected string or nil",2) end | |
| Computer.state.label = label and label:sub(1,32) | |
| end | |
| function api.os.getComputerLabel() | |
| return Computer.state.label | |
| end | |
| function api.os.queueEvent(event, ...) | |
| if type(event) ~= "string" then error("Expected string",2) end | |
| table.insert(Computer.eventQueue, {event, ...}) | |
| end | |
| function api.os.startTimer(nTimeout) | |
| if type(nTimeout) ~= "number" then error("Expected number",2) end | |
| nTimeout = math.ceil(nTimeout*20)/20 | |
| if nTimeout < 0.05 then nTimeout = 0.05 end | |
| Computer.actions.timers[Computer.actions.lastTimer] = math.floor(love.timer.getTime()*20)/20 + nTimeout | |
| Computer.actions.lastTimer = Computer.actions.lastTimer + 1 | |
| return Computer.actions.lastTimer-1 | |
| end | |
| function api.os.setAlarm(nTime) | |
| if type(nTime) ~= "number" then error("Expected number",2) end | |
| if nTime < 0 or nTime > 24 then | |
| error("Number out of range",2) | |
| end | |
| local alarm = { | |
| time = nTime, | |
| day = api.os.day() + (nTime < api.os.time() and 1 or 0) | |
| } | |
| Computer.actions.alarms[Computer.actions.lastAlarm] = alarm | |
| Computer.actions.lastAlarm = Computer.actions.lastAlarm + 1 | |
| return Computer.actions.lastAlarm-1 | |
| end | |
| function api.os.cancelTimer(id) | |
| if type(id) ~= "number" then error("Expected number",2) end | |
| if id == id then | |
| Computer.actions.timers[id] = nil | |
| end | |
| end | |
| function api.os.cancelAlarm(id) | |
| if type(id) ~= "number" then error("Expected number",2) end | |
| if id == id then | |
| Computer.actions.alarms[id] = nil | |
| end | |
| end | |
| function api.os.shutdown() | |
| Computer:stop(false) | |
| end | |
| function api.os.reboot() | |
| Computer:stop(true) -- Reboots on next update/tick | |
| end | |
| api.peripheral = {} | |
| function api.peripheral.isPresent(sSide) | |
| if type(sSide) ~= "string" then error("Expected string",2) end | |
| return Computer.state.peripherals[sSide] ~= nil | |
| end | |
| function api.peripheral.getType(sSide) | |
| if type(sSide) ~= "string" then error("Expected string",2) end | |
| if Computer.state.peripherals[sSide] then return peripheral.types[Computer.state.peripherals[sSide].type] end | |
| return | |
| end | |
| function api.peripheral.getMethods(sSide) | |
| if type(sSide) ~= "string" then error("Expected string",2) end | |
| if Computer.state.peripherals[sSide] then return Computer.state.peripherals[sSide].getMethods() end | |
| return | |
| end | |
| function api.peripheral.call(sSide, sMethod, ...) | |
| if type(sSide) ~= "string" or type(sMethod) ~= "string" then | |
| if sSide == nil or type(sMethod) ~= "string" then | |
| error("Expected string, string",2) | |
| else | |
| error("Expected string",2) | |
| end | |
| end | |
| if not Computer.state.peripherals[sSide] then error("No peripheral attached",2) end | |
| if not Computer.state.peripherals[sSide].cache[sMethod] then | |
| error("No such method " .. sMethod,2) | |
| end | |
| return Computer.state.peripherals[sSide].call(sMethod, ...) | |
| end | |
| api.fs = {} | |
| local function cleanPath(path,wildcard) | |
| local path = path:gsub("\\", "/"):gsub("[%z\1-\31\":<>%?|" .. (wildcard and "" or "%*") .. "]","") | |
| local tPath = {} | |
| for part in path:gmatch("[^/]+") do | |
| if part ~= "" and part ~= "." then | |
| if (part == ".." or part == "...") and #tPath > 0 and tPath[#tPath] ~= ".." then | |
| table.remove(tPath) | |
| else | |
| table.insert(tPath, part:sub(1,255)) | |
| end | |
| end | |
| end | |
| return table.concat(tPath, "/") | |
| end | |
| function api.fs.combine(...) | |
| local basePath, localPath = ... | |
| if type(basePath) ~= "string" or type(localPath) ~= "string" or select("#",...) ~= 2 then | |
| error("Expected string, string",2) | |
| end | |
| return cleanPath(("/" .. basePath .. "/" .. localPath):gsub("\\", "/"), true) | |
| end | |
| local function contains(pathA, pathB) | |
| pathA = cleanPath(pathA) | |
| pathB = cleanPath(pathB) | |
| if pathB == ".." then | |
| return false | |
| elseif pathB:sub(1,3) == "../" then | |
| return false | |
| elseif pathB == pathA then | |
| return true | |
| elseif #pathA == 0 then | |
| return true | |
| else | |
| return pathB:sub(1,#pathA+1) == pathA .. "/" | |
| end | |
| end | |
| local function recurse_spec(results, path, spec) | |
| local segment = spec:match('([^/]*)'):gsub('/', '') | |
| local pattern = '^' .. segment:gsub("[%.%[%]%(%)%%%+%-%?%^%$]","%%%1"):gsub("%z","%%z"):gsub("%*","[^/]-") .. '$' | |
| if api.fs.isDir(path) then | |
| for _, file in ipairs(api.fs.list(path)) do | |
| if file:match(pattern) then | |
| local f = api.fs.combine(path, file) | |
| if spec == segment then | |
| table.insert(results, f) | |
| end | |
| if api.fs.isDir(f) then | |
| recurse_spec(results, f, spec:sub(#segment + 2)) | |
| end | |
| end | |
| end | |
| end | |
| end | |
| function api.fs.getDir(...) | |
| local path = ... | |
| if type(path) ~= "string" or select("#",...) ~= 1 then | |
| error("Expected string",2) | |
| end | |
| path = cleanPath(path, true) | |
| if #path == 0 then | |
| return ".." | |
| else | |
| return path:match("(.*)/") or "" | |
| end | |
| end | |
| function api.fs.find(...) | |
| local spec = ... | |
| if type(spec) ~= "string" or select("#",...) ~= 1 then | |
| error("Expected string",2) | |
| end | |
| spec = cleanPath(spec, true) | |
| local results = {} | |
| recurse_spec(results, '', spec) | |
| return results | |
| end | |
| local fsmodes = {r=FileReadHandle, rb=FileBinaryReadHandle, w=FileWriteHandle, a=FileWriteHandle, wb=FileBinaryWriteHandle, ab=FileBinaryWriteHandle} | |
| function api.fs.open(...) | |
| local path, mode = ... | |
| if type(path) ~= "string" or type(mode) ~= "string" or select("#",...) ~= 2 then | |
| error("Expected string, string",2) | |
| end | |
| path = cleanPath(path) | |
| if path == ".." or path:sub(1,3) == "../" then error("Invalid Path",2) end | |
| local fsfunc = fsmodes[mode] | |
| if fsfunc == nil then error("Unsupported mode",2) end | |
| if vfs.isDirectory(path) then return end | |
| return fsfunc(path, mode == "a" or mode == "ab") | |
| end | |
| function api.fs.list(...) | |
| local path = ... | |
| if type(path) ~= "string" or select("#",...) ~= 1 then | |
| error("Expected string",2) | |
| end | |
| path = cleanPath(path) | |
| if path == ".." or path:sub(1,3) == "../" then error("Invalid Path",2) end | |
| if not vfs.exists(path) or not vfs.isDirectory(path) then | |
| error("Not a directory",2) | |
| end | |
| return vfs.getDirectoryItems(path) | |
| end | |
| function api.fs.exists(...) | |
| local path = ... | |
| if type(path) ~= "string" or select("#",...) ~= 1 then | |
| error("Expected string",2) | |
| end | |
| path = cleanPath(path) | |
| if path == ".." or path:sub(1,3) == "../" then return false end | |
| return vfs.exists(path) | |
| end | |
| function api.fs.isDir(...) | |
| local path = ... | |
| if type(path) ~= "string" or select("#",...) ~= 1 then | |
| error("Expected string",2) | |
| end | |
| path = cleanPath(path) | |
| if path == ".." or path:sub(1,3) == "../" then return false end | |
| return vfs.isDirectory(path) | |
| end | |
| function api.fs.isReadOnly(...) | |
| local path = ... | |
| if type(path) ~= "string" or select("#",...) ~= 1 then | |
| error("Expected string",2) | |
| end | |
| path = cleanPath(path) | |
| return path == "rom" or path:sub(1, 4) == "rom/" | |
| end | |
| function api.fs.getName(...) | |
| local path = ... | |
| if type(path) ~= "string" or select("#",...) ~= 1 then | |
| error("Expected string",2) | |
| end | |
| path = cleanPath(path, true) | |
| if path == "" then | |
| return "root" | |
| else | |
| return path:match(".*/(.+)") or path | |
| end | |
| end | |
| function api.fs.getDrive(...) | |
| local path = ... | |
| if type(path) ~= "string" or select("#",...) ~= 1 then | |
| error("Expected string",2) | |
| end | |
| path = cleanPath(path) | |
| if path == ".." or path:sub(1,3) == "../" then error("Invalid Path",2) end | |
| if not vfs.exists(path) then | |
| return | |
| end | |
| local mountEntry = vfs.getMountContainer(path) | |
| return mountEntry[4] | |
| end | |
| function api.fs.getSize(...) | |
| local path = ... | |
| if type(path) ~= "string" or select("#",...) ~= 1 then | |
| error("Expected string",2) | |
| end | |
| path = cleanPath(path) | |
| if path == ".." or path:sub(1,3) == "../" then error("Invalid Path",2) end | |
| if vfs.exists(path) ~= true then | |
| error("No such file",2) | |
| end | |
| if vfs.isDirectory(path) then | |
| return 0 | |
| end | |
| return vfs.getSize(path) | |
| end | |
| function api.fs.getFreeSpace(...) | |
| local path = ... | |
| if type(path) ~= "string" or select("#",...) ~= 1 then | |
| error("Expected string",2) | |
| end | |
| path = cleanPath(path) | |
| if path == ".." or path:sub(1,3) == "../" then error("Invalid Path",2) end | |
| if path == "rom" or path:sub(1, 4) == "rom/" then | |
| return 0 | |
| end | |
| return math.huge | |
| end | |
| function api.fs.makeDir(...) | |
| local path = ... | |
| if type(path) ~= "string" or select("#",...) ~= 1 then | |
| error("Expected string",2) | |
| end | |
| path = cleanPath(path) | |
| if path == ".." or path:sub(1,3) == "../" then error("Invalid Path",2) end | |
| if path == "rom" or path:sub(1, 4) == "rom/" then | |
| error("Access Denied",2) | |
| end | |
| if vfs.exists(path) and not vfs.isDirectory(path) then | |
| error("File exists",2) | |
| end | |
| vfs.createDirectory(path) | |
| end | |
| local function deltree(sFolder) | |
| local tObjects = vfs.getDirectoryItems(sFolder) | |
| if tObjects then | |
| for _, sObject in pairs(tObjects) do | |
| local pObject = sFolder.."/"..sObject | |
| if vfs.isDirectory(pObject) then | |
| deltree(pObject) | |
| end | |
| vfs.remove(pObject) | |
| end | |
| end | |
| return vfs.remove(sFolder) | |
| end | |
| api._deltree = deltree | |
| local function copytree(sFolder, sToFolder) | |
| if not vfs.isDirectory(sFolder) then | |
| vfs.write(sToFolder, vfs.read(sFolder)) | |
| return | |
| end | |
| vfs.createDirectory(sToFolder) | |
| local tObjects = vfs.getDirectoryItems(sFolder) | |
| if tObjects then | |
| for _, sObject in pairs(tObjects) do | |
| local pObject = sFolder.."/"..sObject | |
| local pToObject = sToFolder.."/"..sObject | |
| if vfs.isDirectory(pObject) then | |
| vfs.createDirectory(pToObject) | |
| copytree(pObject,pToObject) | |
| else | |
| vfs.write(pToObject, vfs.read(pObject)) | |
| end | |
| end | |
| end | |
| end | |
| api._copytree = copytree | |
| function api.fs.move(...) | |
| local fromPath, toPath = ... | |
| if type(fromPath) ~= "string" or type(toPath) ~= "string" or select("#",...) ~= 2 then | |
| error("Expected string, string",2) | |
| end | |
| fromPath = cleanPath(fromPath) | |
| if fromPath == ".." or fromPath:sub(1,3) == "../" then error("Invalid Path",2) end | |
| toPath = cleanPath(toPath) | |
| if toPath == ".." or toPath:sub(1,3) == "../" then error("Invalid Path",2) end | |
| if fromPath == "rom" or fromPath:sub(1, 4) == "rom/" or | |
| toPath == "rom" or toPath:sub(1, 4) == "rom/" then | |
| error("Access denied",2) | |
| end | |
| if not vfs.exists(fromPath) then | |
| error("No such file",2) | |
| elseif vfs.exists(toPath) then | |
| error("File exists",2) | |
| elseif contains(fromPath, toPath) then | |
| error("Can't move a directory inside itself",2) | |
| end | |
| copytree(fromPath, toPath) | |
| deltree(fromPath) | |
| end | |
| function api.fs.copy(...) | |
| local fromPath, toPath = ... | |
| if type(fromPath) ~= "string" or type(toPath) ~= "string" or select("#",...) ~= 2 then | |
| error("Expected string, string",2) | |
| end | |
| fromPath = cleanPath(fromPath) | |
| if fromPath == ".." or fromPath:sub(1,3) == "../" then error("Invalid Path",2) end | |
| toPath = cleanPath(toPath) | |
| if toPath == ".." or toPath:sub(1,3) == "../" then error("Invalid Path",2) end | |
| if toPath == "rom" or toPath:sub(1, 4) == "rom/" then | |
| error("Access denied",2) | |
| elseif not vfs.exists(fromPath) then | |
| error("No such file",2) | |
| elseif vfs.exists(toPath) then | |
| error("File exists",2) | |
| elseif contains(fromPath, toPath) then | |
| error("Can't copy a directory inside itself",2) | |
| end | |
| copytree(fromPath, toPath) | |
| end | |
| function api.fs.delete(...) | |
| local path = ... | |
| if type(path) ~= "string" or select("#",...) ~= 1 then | |
| error("Expected string",2) | |
| end | |
| path = cleanPath(path) | |
| if path == ".." or path:sub(1,3) == "../" then error("Invalid Path",2) end | |
| if path == "rom" or path:sub(1, 4) == "rom/" or vfs.isMountPath(path) then | |
| error("Access Denied",2) | |
| end | |
| deltree(path) | |
| end | |
| api.redstone = {} | |
| local outputs = {top=0, bottom=0, left=0, right=0, front=0, back=0} | |
| local bundled = {top=0, bottom=0, left=0, right=0, front=0, back=0} | |
| function api.redstone.getSides() | |
| return {"top","bottom","left","right","front","back"} | |
| end | |
| function api.redstone.getInput(side) | |
| if type(side) ~= "string" then | |
| error("Expected string",2) | |
| elseif side~="top" and side~="bottom" and side~="left" and side~="right" and side~="front" and side~="back" then | |
| error("Invalid side.",2) | |
| end | |
| return false | |
| end | |
| function api.redstone.setOutput(side, value) | |
| if type(side) ~= "string" or type(value) ~= "boolean" then | |
| error("Expected string, boolean",2) | |
| elseif side~="top" and side~="bottom" and side~="left" and side~="right" and side~="front" and side~="back" then | |
| error("Invalid side.",2) | |
| end | |
| outputs[side] = value and 15 or 0 | |
| end | |
| function api.redstone.getOutput(side) | |
| if type(side) ~= "string" then | |
| error("Expected string",2) | |
| elseif side~="top" and side~="bottom" and side~="left" and side~="right" and side~="front" and side~="back" then | |
| error("Invalid side.",2) | |
| end | |
| return outputs[side] > 0 | |
| end | |
| function api.redstone.getAnalogInput(side) | |
| if type(side) ~= "string" then | |
| error("Expected string",2) | |
| elseif side~="top" and side~="bottom" and side~="left" and side~="right" and side~="front" and side~="back" then | |
| error("Invalid side.",2) | |
| end | |
| return 0 | |
| end | |
| function api.redstone.setAnalogOutput(side, strength) | |
| if type(side) ~= "string" or type(strength) ~= "number" then | |
| error("Expected string, number",2) | |
| elseif side~="top" and side~="bottom" and side~="left" and side~="right" and side~="front" and side~="back" then | |
| error("Invalid side.",2) | |
| elseif strength <= -1 or strength >= 16 then | |
| error("Expected number in range 0-15",2) | |
| end | |
| outputs[side] = math.floor(strength) | |
| end | |
| function api.redstone.getAnalogOutput(side) | |
| if type(side) ~= "string" then | |
| error("Expected string",2) | |
| elseif side~="top" and side~="bottom" and side~="left" and side~="right" and side~="front" and side~="back" then | |
| error("Invalid side.",2) | |
| end | |
| return outputs[side] | |
| end | |
| function api.redstone.getAnalogueInput(side) | |
| if type(side) ~= "string" then | |
| error("Expected string",2) | |
| elseif side~="top" and side~="bottom" and side~="left" and side~="right" and side~="front" and side~="back" then | |
| error("Invalid side.",2) | |
| end | |
| return 0 | |
| end | |
| function api.redstone.setAnalogueOutput(side, strength) | |
| if type(side) ~= "string" or type(strength) ~= "number" then | |
| error("Expected string, number",2) | |
| elseif side~="top" and side~="bottom" and side~="left" and side~="right" and side~="front" and side~="back" then | |
| error("Invalid side.",2) | |
| elseif strength <= -1 or strength >= 16 then | |
| error("Expected number in range 0-15",2) | |
| end | |
| outputs[side] = math.floor(strength) | |
| end | |
| function api.redstone.getAnalogueOutput(side) | |
| if type(side) ~= "string" then | |
| error("Expected string",2) | |
| elseif side~="top" and side~="bottom" and side~="left" and side~="right" and side~="front" and side~="back" then | |
| error("Invalid side.",2) | |
| end | |
| return outputs[side] | |
| end | |
| function api.redstone.getBundledInput(side) | |
| if type(side) ~= "string" then | |
| error("Expected string",2) | |
| elseif side~="top" and side~="bottom" and side~="left" and side~="right" and side~="front" and side~="back" then | |
| error("Invalid side.",2) | |
| end | |
| return 0 | |
| end | |
| function api.redstone.getBundledOutput(side) | |
| if type(side) ~= "string" then | |
| error("Expected string",2) | |
| elseif side~="top" and side~="bottom" and side~="left" and side~="right" and side~="front" and side~="back" then | |
| error("Invalid side.",2) | |
| end | |
| return bundled[side] | |
| end | |
| function api.redstone.setBundledOutput(side, colors) | |
| if type(side) ~= "string" or type(colors) ~= "number" then | |
| error("Expected string, number",2) | |
| elseif side~="top" and side~="bottom" and side~="left" and side~="right" and side~="front" and side~="back" then | |
| error("Invalid side.",2) | |
| end | |
| bundled[side] = math.max(math.min(math.floor(colors),2^31),0) | |
| end | |
| function api.redstone.testBundledInput(side, color) | |
| if type(side) ~= "string" or type(color) ~= "number" then | |
| error("Expected string, number",2) | |
| elseif side~="top" and side~="bottom" and side~="left" and side~="right" and side~="front" and side~="back" then | |
| error("Invalid side.",2) | |
| end | |
| return color == 0 or color ~= color | |
| end | |
| api.bit = {} | |
| local function cleanValue(val) | |
| if val ~= val or val == -math.huge then | |
| return 0 | |
| elseif val == math.huge then | |
| return -1 | |
| end | |
| return val | |
| end | |
| function api.bit.norm(val) | |
| while val < 0 do val = val + 4294967296 end | |
| return val | |
| end | |
| function api.bit.blshift(n, bits) | |
| if type(n) ~= "number" or type(bits) ~= "number" then | |
| error("Expected number, number",2) | |
| end | |
| n,bits=cleanValue(n),cleanValue(bits) | |
| return api.bit.norm(bit.lshift(n, bits)) | |
| end | |
| function api.bit.brshift(n, bits) | |
| if type(n) ~= "number" or type(bits) ~= "number" then | |
| error("Expected number, number",2) | |
| end | |
| n,bits=cleanValue(n),cleanValue(bits) | |
| return api.bit.norm(bit.arshift(n, bits)) | |
| end | |
| function api.bit.blogic_rshift(n, bits) | |
| if type(n) ~= "number" or type(bits) ~= "number" then | |
| error("Expected number, number",2) | |
| end | |
| n,bits=cleanValue(n),cleanValue(bits) | |
| return api.bit.norm(bit.rshift(n, bits)) | |
| end | |
| function api.bit.bxor(m, n) | |
| if type(m) ~= "number" or type(n) ~= "number" then | |
| error("Expected number, number",2) | |
| end | |
| m,n=cleanValue(m),cleanValue(n) | |
| return api.bit.norm(bit.bxor(m, n)) | |
| end | |
| function api.bit.bor(m, n) | |
| if type(m) ~= "number" or type(n) ~= "number" then | |
| error("Expected number, number",2) | |
| end | |
| m,n=cleanValue(m),cleanValue(n) | |
| return api.bit.norm(bit.bor(m, n)) | |
| end | |
| function api.bit.band(m, n) | |
| if type(m) ~= "number" or type(n) ~= "number" then | |
| error("Expected number, number",2) | |
| end | |
| m,n=cleanValue(m),cleanValue(n) | |
| return api.bit.norm(bit.band(m, n)) | |
| end | |
| function api.bit.bnot(n) | |
| if type(n) ~= "number" then | |
| error("Expected number",2) | |
| end | |
| n=cleanValue(n) | |
| return api.bit.norm(bit.bnot(n)) | |
| end | |
| local randseed=ffi.new("uint64_t") | |
| function rnext(bits) | |
| randseed=(randseed*0x5DEECE66D+0xB)%2^48 | |
| return randseed/(2^(48-bits)) | |
| end | |
| function rnextInt(n) | |
| if bit.band(n,-n)==bit.tobit(n) then | |
| return tonumber((n*rnext(31))/2^31) | |
| end | |
| local val | |
| repeat | |
| local bits=tonumber(rnext(31)) | |
| val=bits%n | |
| until bits-val+(n-1)>=0 | |
| return val | |
| end | |
| api.math=tablecopy(math) | |
| function api.math.randomseed(num) | |
| if type(num)~="number" then | |
| error("bad argument #1: number expected, got "..type(num),2) | |
| end | |
| num=((num==math.huge or num==1/0) and -1) or (num~=num and 0) or math.floor(num) | |
| randseed=(ffi.cast("uint64_t",bit.bxor(math.floor(num/2^32)%2^16,5))*2^32)+tonumber(bit.tohex(bit.bxor(num%2^32,0xDEECE66D)),16) | |
| end | |
| function api.math.random(a,b) | |
| if b==nil then | |
| if a==nil then | |
| local n=tonumber((rnext(26)*(2^27))+rnext(27))/2^53 | |
| if n==1 or n==0 then | |
| return n | |
| end | |
| local c=1 | |
| while n<0.1 do | |
| n=n*10 | |
| c=c*0.1 | |
| end | |
| return n*c | |
| else | |
| if type(a)~="number" then | |
| error("bad argument #1: number expected, got "..type(a),2) | |
| elseif a<1 or a==math.huge or a~=a or a==1/0 then | |
| error("bad argument #1: interval is empty",2) | |
| end | |
| return 1+rnextInt(math.floor(a)) | |
| end | |
| else | |
| if type(a)~="number" then | |
| error("bad argument #1: number expected, got "..type(a),2) | |
| elseif type(b)~="number" then | |
| error("bad argument #2: number expected, got "..type(b),2) | |
| elseif a==math.huge or a~=a or a==1/0 then | |
| error("bad argument #1: interval is empty",2) | |
| elseif b==math.huge or b~=b or b==1/0 or b<a then | |
| error("bad argument #2: interval is empty",2) | |
| end | |
| return a+rnextInt(b+1-a) | |
| end | |
| end | |
| _tostring_DB[coroutine.create] = nil | |
| _tostring_DB[string.gmatch] = "gmatch" | |
| _tostring_DB[api.tostring] = "tostring" | |
| _tostring_DB[api.tonumber] = "tonumber" | |
| _tostring_DB[api.loadstring] = "loadstring" | |
| _tostring_DB[api.inext] = "__inext" | |
| _tostring_DB[api.math.random] = "random" | |
| _tostring_DB[api.math.randomseed] = "randomseed" | |
| _tostring_DB[api.getfenv] = "getfenv" | |
| _tostring_DB[error] = "error" | |
| function api.init() -- Called after this file is loaded! Important. Else api.x is not defined | |
| api.math.randomseed(math.random(0,0xFFFFFFFFFFFF)) | |
| api.env = { | |
| _HOST="1.76 (Minecraft 1.8)", | |
| _LUAJ_VERSION="2.0.3", | |
| _VERSION="Lua 5.1", | |
| __inext = api.inext, | |
| tostring = api.tostring, | |
| tonumber = api.tonumber, | |
| unpack = unpack, | |
| getfenv = api.getfenv, | |
| setfenv = setfenv, | |
| rawequal = rawequal, | |
| rawset = rawset, | |
| rawget = rawget, | |
| setmetatable = setmetatable, | |
| getmetatable = getmetatable, | |
| next = next, | |
| type = type, | |
| select = select, | |
| assert = assert, | |
| error = error, | |
| ipairs = ipairs, | |
| pairs = pairs, | |
| pcall = pcall, | |
| xpcall = xpcall, | |
| loadstring = api.loadstring, | |
| math = api.math, | |
| string = tablecopy(string), | |
| table = tablecopy(table), | |
| coroutine = tablecopy(coroutine), | |
| -- CC apis (BIOS completes api.) | |
| term = { | |
| blit = api.term.blit, | |
| clear = api.term.clear, | |
| clearLine = api.term.clearLine, | |
| getSize = api.term.getSize, | |
| getCursorPos = api.term.getCursorPos, | |
| setCursorPos = api.term.setCursorPos, | |
| getTextColor = api.term.getTextColor, | |
| getTextColour = api.term.getTextColor, | |
| setTextColor = api.term.setTextColor, | |
| setTextColour = api.term.setTextColor, | |
| getBackgroundColor = api.term.getBackgroundColor, | |
| getBackgroundColour = api.term.getBackgroundColor, | |
| setBackgroundColor = api.term.setBackgroundColor, | |
| setBackgroundColour = api.term.setBackgroundColor, | |
| setCursorBlink = api.term.setCursorBlink, | |
| scroll = api.term.scroll, | |
| write = api.term.write, | |
| isColor = api.term.isColor, | |
| isColour = api.term.isColor, | |
| }, | |
| fs = { | |
| getDir = api.fs.getDir, | |
| find = api.fs.find, | |
| open = api.fs.open, | |
| list = api.fs.list, | |
| exists = api.fs.exists, | |
| isDir = api.fs.isDir, | |
| isReadOnly = api.fs.isReadOnly, | |
| getName = api.fs.getName, | |
| getDrive = api.fs.getDrive, | |
| getSize = api.fs.getSize, | |
| getFreeSpace = api.fs.getFreeSpace, | |
| makeDir = api.fs.makeDir, | |
| move = api.fs.move, | |
| copy = api.fs.copy, | |
| delete = api.fs.delete, | |
| combine = api.fs.combine, | |
| }, | |
| os = { | |
| clock = api.os.clock, | |
| getComputerID = function() return 0 end, | |
| computerID = function() return 0 end, | |
| setComputerLabel = api.os.setComputerLabel, | |
| getComputerLabel = api.os.getComputerLabel, | |
| computerLabel = api.os.getComputerLabel, | |
| queueEvent = api.os.queueEvent, | |
| startTimer = api.os.startTimer, | |
| setAlarm = api.os.setAlarm, | |
| cancelTimer = api.os.cancelTimer, | |
| cancelAlarm = api.os.cancelAlarm, | |
| time = api.os.time, | |
| day = api.os.day, | |
| shutdown = api.os.shutdown, | |
| reboot = api.os.reboot, | |
| }, | |
| peripheral = { | |
| isPresent = api.peripheral.isPresent, | |
| getType = api.peripheral.getType, | |
| getMethods = api.peripheral.getMethods, | |
| call = api.peripheral.call, | |
| }, | |
| redstone = { | |
| getSides = api.redstone.getSides, | |
| getInput = api.redstone.getInput, | |
| getOutput = api.redstone.getOutput, | |
| getBundledInput = api.redstone.getBundledInput, | |
| getBundledOutput = api.redstone.getBundledOutput, | |
| getAnalogInput = api.redstone.getAnalogInput, | |
| getAnalogOutput = api.redstone.getAnalogOutput, | |
| getAnalogueInput = api.redstone.getAnalogueInput, | |
| getAnalogueOutput = api.redstone.getAnalogueOutput, | |
| setOutput = api.redstone.setOutput, | |
| setBundledOutput = api.redstone.setBundledOutput, | |
| setAnalogOutput = api.redstone.setAnalogOutput, | |
| setAnalogueOutput = api.redstone.setAnalogueOutput, | |
| testBundledInput = api.redstone.testBundledInput, | |
| }, | |
| bit = { | |
| blshift = api.bit.blshift, | |
| brshift = api.bit.brshift, | |
| blogic_rshift = api.bit.blogic_rshift, | |
| bxor = api.bit.bxor, | |
| bor = api.bit.bor, | |
| band = api.bit.band, | |
| bnot = api.bit.bnot, | |
| }, | |
| } | |
| if _conf.enableAPI_http then | |
| api.env.http = { | |
| checkURL = api.http.checkURL, | |
| request = api.http.request, | |
| } | |
| end | |
| if _conf.enableAPI_cclite then | |
| api.env.cclite = { | |
| peripheralAttach = api.cclite.peripheralAttach, | |
| peripheralDetach = api.cclite.peripheralDetach, | |
| getMethods = api.cclite.getMethods, | |
| call = api.cclite.call, | |
| log = print, | |
| message = api.cclite.message, | |
| traceback = debug.traceback, | |
| } | |
| end | |
| api.env.rs = api.env.redstone | |
| api.env.math.mod = nil | |
| api.env.string.gfind = nil | |
| api.env._G = api.env | |
| end | |
| api.init() |