Advertisement
joshgreatuk

Boot (minios)

Oct 27th, 2018
152
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 41.23 KB | None | 0 0
  1. _G._OSNAME = "miniOS"
  2. _G._OSVER = "0.6.1.5"
  3. _G._OSVERSION = _OSNAME .. " " .. _OSVER
  4. _G._OSCREDIT = "miniOS by Skye, based off of OpenOS code from OpenComputers.\nminiOS code is under BSD 2-clause license, OpenOS code is under the MIT liecence."
  5.  
  6. --component code
  7. function component_code()
  8. local adding = {}
  9. local removing = {}
  10. local primaries = {}
  11.  
  12. -------------------------------------------------------------------------------
  13.  
  14. -- This allows writing component.modem.open(123) instead of writing
  15. -- component.getPrimary("modem").open(123), which may be nicer to read.
  16. setmetatable(component, { __index = function(_, key)
  17.                                       return component.getPrimary(key)
  18.                                     end})
  19.  
  20. function component.get(address, componentType)
  21.   checkArg(1, address, "string")
  22.   checkArg(2, componentType, "string", "nil")
  23.   for c in component.list(componentType, true) do
  24.     if c:sub(1, address:len()) == address then
  25.       return c
  26.     end
  27.   end
  28.   return nil, "no such component"
  29. end
  30.  
  31. function component.isAvailable(componentType)
  32.   checkArg(1, componentType, "string")
  33.   if not primaries[componentType] then
  34.     -- This is mostly to avoid out of memory errors preventing proxy
  35.     -- creation cause confusion by trying to create the proxy again,
  36.     -- causing the oom error to be thrown again.
  37.     component.setPrimary(componentType, component.list(componentType, true)())
  38.   end
  39.   return primaries[componentType] ~= nil
  40. end
  41.  
  42. function component.isPrimary(address)
  43.   local componentType = component.type(address)
  44.   if componentType then
  45.     if component.isAvailable(componentType) then
  46.       return primaries[componentType].address == address
  47.     end
  48.   end
  49.   return false
  50. end
  51.  
  52. function component.getPrimary(componentType)
  53.   checkArg(1, componentType, "string")
  54.   assert(component.isAvailable(componentType),
  55.     "no primary '" .. componentType .. "' available")
  56.   return primaries[componentType]
  57. end
  58.  
  59. function component.setPrimary(componentType, address)
  60.   checkArg(1, componentType, "string")
  61.   checkArg(2, address, "string", "nil")
  62.   if address ~= nil then
  63.     address = component.get(address, componentType)
  64.     assert(address, "no such component")
  65.   end
  66.  
  67.   local wasAvailable = primaries[componentType]
  68.   if wasAvailable and address == wasAvailable.address then
  69.     return
  70.   end
  71.   local wasAdding = adding[componentType]
  72.   if wasAdding and address == wasAdding.address then
  73.     return
  74.   end
  75.   if wasAdding then
  76.     event.cancel(wasAdding.timer)
  77.   end
  78.   primaries[componentType] = nil
  79.   adding[componentType] = nil
  80.  
  81.   local primary = address and component.proxy(address) or nil
  82.   if wasAvailable then
  83.     computer.pushSignal("component_unavailable", componentType)
  84.   end
  85.   if primary then
  86.     if wasAvailable or wasAdding then
  87.       adding[componentType] = {
  88.         address=address,
  89.         timer=event.timer(0.1, function()
  90.           adding[componentType] = nil
  91.           primaries[componentType] = primary
  92.           computer.pushSignal("component_available", componentType)
  93.         end)
  94.       }
  95.     else
  96.       primaries[componentType] = primary
  97.       computer.pushSignal("component_available", componentType)
  98.     end
  99.   end
  100. end
  101.  
  102. -------------------------------------------------------------------------------
  103.  
  104. local function onComponentAdded(_, address, componentType)
  105.   if not (primaries[componentType] or adding[componentType]) then
  106.     component.setPrimary(componentType, address)
  107.   end
  108. end
  109.  
  110. local function onComponentRemoved(_, address, componentType)
  111.   if primaries[componentType] and primaries[componentType].address == address or
  112.      adding[componentType] and adding[componentType].address == address
  113.   then
  114.     component.setPrimary(componentType, component.list(componentType, true)())
  115.   end
  116. end
  117.  
  118. event.listen("component_added", onComponentAdded)
  119. event.listen("component_removed", onComponentRemoved)
  120. end
  121. --text libary
  122. function text_code()
  123.   local text = {}
  124.  
  125.   function text.detab(value, tabWidth)
  126.     checkArg(1, value, "string")
  127.     checkArg(2, tabWidth, "number", "nil")
  128.     tabWidth = tabWidth or 8
  129.     local function rep(match)
  130.       local spaces = tabWidth - match:len() % tabWidth
  131.       return match .. string.rep(" ", spaces)
  132.     end
  133.     local result = value:gsub("([^\n]-)\t", rep) -- truncate results
  134.     return result
  135.   end
  136.  
  137.   function text.padRight(value, length)
  138.     checkArg(1, value, "string", "nil")
  139.     checkArg(2, length, "number")
  140.     if not value or unicode.len(value) == 0 then
  141.       return string.rep(" ", length)
  142.     else
  143.       return value .. string.rep(" ", length - unicode.len(value))
  144.     end
  145.   end
  146.  
  147.   function text.padLeft(value, length)
  148.     checkArg(1, value, "string", "nil")
  149.     checkArg(2, length, "number")
  150.     if not value or unicode.len(value) == 0 then
  151.       return string.rep(" ", length)
  152.     else
  153.       return string.rep(" ", length - unicode.len(value)) .. value
  154.     end
  155.   end
  156.  
  157.   function text.trim(value) -- from http://lua-users.org/wiki/StringTrim
  158.     local from = string.match(value, "^%s*()")
  159.     return from > #value and "" or string.match(value, ".*%S", from)
  160.   end
  161.  
  162.   function text.wrap(value, width, maxWidth)
  163.     checkArg(1, value, "string")
  164.     checkArg(2, width, "number")
  165.     checkArg(3, maxWidth, "number")
  166.     local line, nl = value:match("([^\r\n]*)(\r?\n?)") -- read until newline
  167.     if unicode.len(line) > width then -- do we even need to wrap?
  168.       local partial = unicode.sub(line, 1, width)
  169.       local wrapped = partial:match("(.*[^a-zA-Z0-9._()'`=])")
  170.       if wrapped or unicode.len(line) > maxWidth then
  171.         partial = wrapped or partial
  172.         return partial, unicode.sub(value, unicode.len(partial) + 1), true
  173.       else
  174.         return "", value, true -- write in new line.
  175.       end
  176.     end
  177.     local start = unicode.len(line) + unicode.len(nl) + 1
  178.     return line, start <= unicode.len(value) and unicode.sub(value, start) or nil, unicode.len(nl) > 0
  179.   end
  180.  
  181.   function text.wrappedLines(value, width, maxWidth)
  182.     local line, nl
  183.     return function()
  184.       if value then
  185.         line, value, nl = text.wrap(value, width, maxWidth)
  186.         return line
  187.       end
  188.     end
  189.   end
  190.  
  191.   -------------------------------------------------------------------------------
  192.  
  193.   function text.tokenize(value)
  194.     checkArg(1, value, "string")
  195.     local tokens, token = {}, ""
  196.     local escaped, quoted, start = false, false, -1
  197.     for i = 1, unicode.len(value) do
  198.       local char = unicode.sub(value, i, i)
  199.       if escaped then -- escaped character
  200.         escaped = false
  201.         token = token .. char
  202.       elseif char == "\\" and quoted ~= "'" then -- escape character?
  203.         escaped = true
  204.         token = token .. char
  205.       elseif char == quoted then -- end of quoted string
  206.         quoted = false
  207.         token = token .. char
  208.       elseif (char == "'" or char == '"') and not quoted then
  209.         quoted = char
  210.         start = i
  211.         token = token .. char
  212.       elseif string.find(char, "%s") and not quoted then -- delimiter
  213.         if token ~= "" then
  214.           table.insert(tokens, token)
  215.           token = ""
  216.         end
  217.       else -- normal char
  218.         token = token .. char
  219.       end
  220.     end
  221.     if quoted then
  222.       return nil, "unclosed quote at index " .. start
  223.     end
  224.     if token ~= "" then
  225.       table.insert(tokens, token)
  226.     end
  227.     return tokens
  228.   end
  229.  
  230.   -------------------------------------------------------------------------------
  231.  
  232.   function text.endswith(s, send)
  233.     return #s >= #send and s:find(send, #s-#send+1, true) and true or false
  234.   end
  235.  
  236.   return text
  237. end
  238. --event code
  239. function event_code()
  240.   local event, listeners, timers = {}, {}, {}
  241.   local lastInterrupt = -math.huge
  242.  
  243.   local function matches(signal, name, filter)
  244.     if name and not (type(signal[1]) == "string" and signal[1]:match(name))
  245.     then
  246.       return false
  247.     end
  248.     for i = 1, filter.n do
  249.       if filter[i] ~= nil and filter[i] ~= signal[i + 1] then
  250.         return false
  251.       end
  252.     end
  253.     return true
  254.   end
  255.  
  256.   local function call(callback, ...)
  257.     local result, message = pcall(callback, ...)
  258.     if not result and type(event.onError) == "function" then
  259.       pcall(event.onError, message)
  260.       return
  261.     end
  262.     return message
  263.   end
  264.  
  265.   local function dispatch(signal, ...)
  266.     if listeners[signal] then
  267.       local function callbacks()
  268.         local list = {}
  269.         for index, listener in ipairs(listeners[signal]) do
  270.           list[index] = listener
  271.         end
  272.         return list
  273.       end
  274.       for _, callback in ipairs(callbacks()) do
  275.         if call(callback, signal, ...) == false then
  276.           event.ignore(signal, callback) -- alternative method of removing a listener
  277.         end
  278.       end
  279.     end
  280.   end
  281.  
  282.   local function tick()
  283.     local function elapsed()
  284.       local list = {}
  285.       for id, timer in pairs(timers) do
  286.         if timer.after <= computer.uptime() then
  287.           table.insert(list, timer.callback)
  288.           timer.times = timer.times - 1
  289.           if timer.times <= 0 then
  290.             timers[id] = nil
  291.           else
  292.             timer.after = computer.uptime() + timer.interval
  293.           end
  294.         end
  295.       end
  296.       return list
  297.     end
  298.     for _, callback in ipairs(elapsed()) do
  299.       call(callback)
  300.     end
  301.   end
  302.  
  303.   -------------------------------------------------------------------------------
  304.  
  305.   function event.cancel(timerId)
  306.     checkArg(1, timerId, "number")
  307.     if timers[timerId] then
  308.       timers[timerId] = nil
  309.       return true
  310.     end
  311.     return false
  312.   end
  313.  
  314.   function event.ignore(name, callback)
  315.     checkArg(1, name, "string")
  316.     checkArg(2, callback, "function")
  317.     if listeners[name] then
  318.       for i = 1, #listeners[name] do
  319.         if listeners[name][i] == callback then
  320.           table.remove(listeners[name], i)
  321.           if #listeners[name] == 0 then
  322.             listeners[name] = nil
  323.           end
  324.           return true
  325.         end
  326.       end
  327.     end
  328.     return false
  329.   end
  330.  
  331.   function event.listen(name, callback)
  332.     checkArg(1, name, "string")
  333.     checkArg(2, callback, "function")
  334.     if listeners[name] then
  335.       for i = 1, #listeners[name] do
  336.         if listeners[name][i] == callback then
  337.           return false
  338.         end
  339.       end
  340.     else
  341.       listeners[name] = {}
  342.     end
  343.     table.insert(listeners[name], callback)
  344.     return true
  345.   end
  346.  
  347.   function event.onError(message)
  348.     local log = io.open("/tmp/event.log", "a")
  349.     if log then
  350.       log:write(message .. "\n")
  351.       log:close()
  352.     end
  353.   end
  354.  
  355.   function event.pull(...)
  356.     local args = table.pack(...)
  357.     local seconds, name, filter
  358.     if type(args[1]) == "string" then
  359.       name = args[1]
  360.       filter = table.pack(table.unpack(args, 2, args.n))
  361.     else
  362.       checkArg(1, args[1], "number", "nil")
  363.       checkArg(2, args[2], "string", "nil")
  364.       seconds = args[1]
  365.       name = args[2]
  366.       filter = table.pack(table.unpack(args, 3, args.n))
  367.     end
  368.  
  369.     local hasFilter = name ~= nil
  370.     if not hasFilter then
  371.       for i = 1, filter.n do
  372.         hasFilter = hasFilter or filter[i] ~= nil
  373.       end
  374.     end
  375.  
  376.     local deadline = seconds and
  377.                      (computer.uptime() + seconds) or
  378.                      (hasFilter and math.huge or 0)
  379.     repeat
  380.       local closest = seconds and deadline or math.huge
  381.       for _, timer in pairs(timers) do
  382.         closest = math.min(closest, timer.after)
  383.       end
  384.       local signal = table.pack(computer.pullSignal(closest - computer.uptime()))
  385.       if signal.n > 0 then
  386.         dispatch(table.unpack(signal, 1, signal.n))
  387.       end
  388.       tick()
  389.       if event.shouldInterrupt() then
  390.         lastInterrupt = computer.uptime()
  391.         error("interrupted", 0)
  392.       end
  393.       if not (seconds or hasFilter) or matches(signal, name, filter) then
  394.         return table.unpack(signal, 1, signal.n)
  395.       end
  396.     until computer.uptime() >= deadline
  397.   end
  398.  
  399.   function event.shouldInterrupt()
  400.     return computer.uptime() - lastInterrupt > 1 and
  401.            keyboard.isControlDown() and
  402.            keyboard.isAltDown() and
  403.            keyboard.isKeyDown(keyboard.keys.c)
  404.   end
  405.  
  406.   function event.timer(interval, callback, times)
  407.     checkArg(1, interval, "number")
  408.     checkArg(2, callback, "function")
  409.     checkArg(3, times, "number", "nil")
  410.     local id
  411.     repeat
  412.       id = math.floor(math.random(1, 0x7FFFFFFF))
  413.     until not timers[id]
  414.     timers[id] = {
  415.       interval = interval,
  416.       after = computer.uptime() + interval,
  417.       callback = callback,
  418.       times = times or 1
  419.     }
  420.     return id
  421.   end
  422.  
  423.   -------------------------------------------------------------------------------
  424.  
  425.   return event
  426. end
  427. --filesystem code
  428. function fs_code()
  429.   local fs = {}
  430.   fs.drive = {}
  431.   --drive mapping table, initilized later
  432.   fs.drive._map = {}
  433.   --converts a drive letter into a proxy
  434.   function fs.drive.letterToProxy(letter)
  435.     return fs.drive._map[letter]
  436.   end
  437.   --finds the proxy associated with the letter
  438.   function fs.drive.proxyToLetter(proxy)
  439.     for l,p in pairs(fs.drive._map) do
  440.       if p == proxy then return l end
  441.     end
  442.     return nil
  443.   end
  444.   --maps a proxy to a letter
  445.   function fs.drive.mapProxy(letter, proxy)
  446.     fs.drive._map[letter] = proxy
  447.   end
  448.   --finds the address of a drive letter.
  449.   function fs.drive.toAddress(letter)
  450.     return fs.drive._map[letter].address
  451.   end
  452.   --finds the drive letter mapped to an address
  453.   function fs.drive.toLetter(address)
  454.     for l,p in pairs(fs.drive._map) do
  455.       if p.address == address then return l end
  456.     end
  457.     return nil
  458.   end
  459.   function fs.drive.mapAddress(letter, address)
  460.     --print("mapAddress")
  461.     fs.drive._map[letter] = fs.proxy(address)
  462.   end
  463.   function fs.drive.autoMap(address) --returns the letter if mapped OR already mapped, false if not.
  464.     --print("autoMap")
  465.     --we get the address and see if it already is mapped...
  466.     local l = fs.drive.toLetter(address)
  467.     if l then return l end
  468.     --then we take the address and attempt to map it
  469.     --start at A:  
  470.     l = "A"
  471.     while true do
  472.         --see if it is mapped and then go to the next letter...
  473.         if fs.drive._map[l] then l = ('ABCDEFGHIJKLMNOPQRSTUVWXYZ_'):match(l..'(.)') else fs.drive.mapAddress(l, address) return l end
  474.         --if we got to the end, fail
  475.         if l == "_" then return false end
  476.     end
  477.   end
  478.   function fs.drive.listProxy()
  479.     local t = fs.drive._map
  480.     local p = {}
  481.     for n in pairs(t) do table.insert(p, n) end
  482.     table.sort(p, f)
  483.     local i = 0      -- iterator variable
  484.     local iter = function ()   -- iterator function
  485.       i = i + 1
  486.       if p[i] == nil then return nil
  487.       else return p[i], t[p[i]]
  488.       end
  489.     end
  490.     return iter
  491.   end
  492.   function fs.drive.list()
  493.     local i = 0      -- iterator variable
  494.     local proxyIter = fs.drive.listProxy()
  495.     local iter = function ()   -- iterator function
  496.       l, p = proxyIter()
  497.       if not l then return nil end
  498.       return l, p.address
  499.     end
  500.     return iter
  501.   end
  502.   fs.drive._current = "A" --as the boot drive is A:
  503.   function fs.drive.setcurrent(letter)
  504.     letter = letter:upper()
  505.     if not fs.drive._map[letter] then error("Invalid Drive", 2) end
  506.     fs.drive._current = letter
  507.   end
  508.   function fs.drive.drivepathSplit(mixed)
  509.     local drive = fs.drive._current
  510.     local path
  511.     if string.sub(mixed, 2,2) == ":" then
  512.       drive = string.sub(mixed, 1,1):upper()
  513.       path = string.sub(mixed, 3)
  514.     else
  515.       path = mixed
  516.     end
  517.     return drive, path
  518.   end
  519.   function fs.drive.getcurrent() return fs.drive._current end
  520.   function fs.invoke(method, ...) return fs.drive._map[fs.drive._current][method](...) end
  521.   function fs.proxy(filter)
  522.     checkArg(1, filter, "string")
  523.     local address
  524.     for c in component.list("filesystem") do
  525.       if component.invoke(c, "getLabel") == filter then
  526.         address = c
  527.         break
  528.       end
  529.       if filter:sub(2,2) == ":" then
  530.         if fs.drive.toAddress(filter:sub(1,1)) == c then address = c break end
  531.       end
  532.       if c:sub(1, filter:len()) == filter then
  533.         address = c
  534.         break
  535.       end
  536.     end
  537.     if not address then
  538.       return nil, "no such file system"
  539.     end
  540.     return component.proxy(address)
  541.   end
  542.   function fs.open(file, mode)
  543.     local drive, handle, proxy
  544.     drive, path = fs.drive.drivepathSplit(file)
  545.     proxy = fs.drive.letterToProxy(drive)
  546.     handle, reason = proxy.open(path, mode or 'r')
  547.     if not handle then return nil, reason end
  548.     return {_handle = handle, _proxy = proxy}
  549.   end
  550.   function fs.write(handle, data) return handle._proxy.write(handle._handle, data) end
  551.   function fs.read(handle, length) return handle._proxy.read(handle._handle, length or math.huge) end
  552.   function fs.close(handle) return handle._proxy.close(handle._handle) end
  553.   function fs.isDirectory(path)
  554.     local drive
  555.     drive, path = fs.drive.drivepathSplit(path)
  556.     return fs.drive.letterToProxy(drive).isDirectory(path)
  557.   end
  558.   function fs.exists(path)
  559.     local drive
  560.     drive, path = fs.drive.drivepathSplit(path)
  561.     return fs.drive.letterToProxy(drive).exists(path)
  562.   end
  563.   function fs.remove(path)
  564.     local drive
  565.     drive, path = fs.drive.drivepathSplit(path)
  566.     return fs.drive.letterToProxy(drive).remove(path)
  567.   end
  568.   function fs.copy(fromPath, toPath)
  569.     if fs.isDirectory(fromPath) then
  570.       return nil, "cannot copy folders"
  571.     end
  572.     local input, reason = fs.open(fromPath, "rb")
  573.     if not input then
  574.       return nil, reason
  575.     end
  576.     local output, reason = fs.open(toPath, "wb")
  577.     if not output then
  578.       fs.close(input)
  579.     return nil, reason
  580.     end
  581.     repeat
  582.       local buffer, reason = filesystem.read(input)
  583.       if not buffer and reason then
  584.         return nil, reason
  585.       elseif buffer then
  586.         local result, reason = filesystem.write(output, buffer)
  587.         if not result then
  588.           filesystem.close(input)
  589.           filesystem.close(output)
  590.           return nil, reason
  591.           end
  592.         end
  593.     until not buffer
  594.     filesystem.close(input)
  595.     filesystem.close(output)
  596.     return true
  597.   end
  598.   function fs.rename(path1, path2)
  599.     local drive
  600.     drive, path = fs.drive.drivepathSplit(path)
  601.     return fs.drive.letterToProxy(drive).rename(path1, path2)
  602.   end
  603.   function fs.makeDirectory(path)
  604.     local drive
  605.     drive, path = fs.drive.drivepathSplit(path)
  606.     return fs.drive.letterToProxy(drive).makeDirectory(path)
  607.   end
  608.   function fs.list(path)
  609.     local drive
  610.     drive, path = fs.drive.drivepathSplit(path)
  611.  
  612.     local i = 0
  613.     local t = fs.drive.letterToProxy(drive).list(path)
  614.     local n = #t
  615.     return function()
  616.       i = i + 1
  617.       if i <= n then return t[i] end
  618.       return nil
  619.     end
  620.   end
  621.   function fs.get(path)
  622.     local drive
  623.     drive, path = fs.drive.drivepathSplit(path)
  624.     drive = fs.drive.letterToProxy(drive)
  625.     if not drive then return nil, "no such file system"
  626.     else return drive, path end
  627.   end
  628.  
  629.   --handle inserted and removed filesystems
  630.   local function onComponentAdded(_, address, componentType)
  631.     if componentType == "filesystem" then
  632.         fs.drive.autoMap(address)
  633.     end
  634.   end
  635.   local function onComponentRemoved(_, address, componentType)
  636.     if componentType == "filesystem" then
  637.       fs.drive.mapAddress(fs.drive.toLetter(address), nil)
  638.     end
  639.   end
  640.   event.listen("component_added", onComponentAdded)
  641.   event.listen("component_removed", onComponentRemoved)
  642.   local function driveInit()
  643.     local boot = fs.proxy(computer.getBootAddress())
  644.     local temp = fs.proxy(computer.tmpAddress())
  645.     fs.drive._map = { ["A"]=boot, ["X"]=temp }
  646.   end
  647.   driveInit()
  648.   --return the API
  649.   return fs
  650. end
  651. --terminal code
  652. function terminal_code()
  653.   local term = {}
  654.   local cursorX, cursorY = 1, 1
  655.   local cursorBlink = nil
  656.   --- quick and dirty hacks that allow newer programs to run while not actually writing new code
  657.   term.gpu = function() return component.gpu end
  658.   term.getViewport = function() return 0, 0, component.gpu.getResolution() end
  659.   term.getGlobalArea = function(ignored)
  660.     local w,h,dx,dy = term.getViewport(window)
  661.     return dx+1,dy+1,w,h
  662.   end
  663.   term.pull = event.pull
  664.   term.keyboard = function() return component.keyboard end
  665.   term.screen = function() return term.gpu().getScreen() end
  666.  
  667.   local function toggleBlink()
  668.     if term.isAvailable() then
  669.       cursorBlink.state = not cursorBlink.state
  670.       if cursorBlink.state then
  671.         cursorBlink.alt = component.gpu.get(cursorX, cursorY)
  672.         component.gpu.set(cursorX, cursorY, "_")
  673.       else
  674.         component.gpu.set(cursorX, cursorY, cursorBlink.alt)
  675.       end
  676.     end
  677.   end
  678.  
  679.   -------------------------------------------------------------------------------
  680.  
  681.   function term.clear()
  682.     if term.isAvailable() then
  683.       local w, h = component.gpu.getResolution()
  684.       component.gpu.fill(1, 1, w, h, " ")
  685.     end
  686.     cursorX, cursorY = 1, 1
  687.   end
  688.  
  689.   function term.clearLine()
  690.     if term.isAvailable() then
  691.       local w = component.gpu.getResolution()
  692.       component.gpu.fill(1, cursorY, w, 1, " ")
  693.     end
  694.     cursorX = 1
  695.   end
  696.  
  697.   function term.getCursor()
  698.     return cursorX, cursorY
  699.   end
  700.  
  701.   function term.setCursor(col, row)
  702.     checkArg(1, col, "number")
  703.     checkArg(2, row, "number")
  704.     if cursorBlink and cursorBlink.state then
  705.       toggleBlink()
  706.     end
  707.     cursorX = math.floor(col)
  708.     cursorY = math.floor(row)
  709.   end
  710.  
  711.   function term.getCursorBlink()
  712.     return cursorBlink ~= nil
  713.   end
  714.  
  715.   function term.setCursorBlink(enabled)
  716.     checkArg(1, enabled, "boolean")
  717.     if enabled then
  718.       if not cursorBlink then
  719.         cursorBlink = {}
  720.         cursorBlink.id = event.timer(0.5, toggleBlink, math.huge)
  721.         cursorBlink.state = false
  722.       elseif not cursorBlink.state then
  723.         toggleBlink()
  724.       end
  725.     elseif cursorBlink then
  726.       event.cancel(cursorBlink.id)
  727.       if cursorBlink.state then
  728.         toggleBlink()
  729.       end
  730.       cursorBlink = nil
  731.     end
  732.   end
  733.  
  734.   function term.isAvailable()
  735.     return component.isAvailable("gpu") and component.isAvailable("screen")
  736.   end
  737.  
  738.   function term.readKey(echo)
  739.     local blink = term.getCursorBlink()
  740.     term.setCursorBlink(true)
  741.     local ok, name, address, charOrValue, code = pcall(event.pull, "key_down")
  742.       if not ok then
  743.         term.setCursorBlink(blink)
  744.         error("interrupted", 0)
  745.     end
  746.     if name == "key_down" then
  747.       if echo then term.write(charOrValue) end
  748.       term.setCursorBlink(blink)
  749.     end
  750.   end
  751.  
  752.   function term.read(history, dobreak)
  753.     checkArg(1, history, "table", "nil")
  754.     history = history or {}
  755.     table.insert(history, "")
  756.     local offset = term.getCursor() - 1
  757.     local scrollX, scrollY = 0, #history - 1
  758.  
  759.     local function getCursor()
  760.       local cx, cy = term.getCursor()
  761.       return cx - offset + scrollX, 1 + scrollY
  762.     end
  763.  
  764.     local function line()
  765.       local cbx, cby = getCursor()
  766.       return history[cby]
  767.     end
  768.  
  769.     local function setCursor(nbx, nby)
  770.       local w, h = component.gpu.getResolution()
  771.       local cx, cy = term.getCursor()
  772.  
  773.       scrollY = nby - 1
  774.  
  775.       nbx = math.max(1, math.min(unicode.len(history[nby]) + 1, nbx))
  776.       local ncx = nbx + offset - scrollX
  777.       if ncx > w then
  778.         local sx = nbx - (w - offset)
  779.         local dx = math.abs(scrollX - sx)
  780.         scrollX = sx
  781.         component.gpu.copy(1 + offset + dx, cy, w - offset - dx, 1, -dx, 0)
  782.         local str = unicode.sub(history[nby], nbx - (dx - 1), nbx)
  783.         str = text.padRight(str, dx)
  784.         component.gpu.set(1 + math.max(offset, w - dx), cy, unicode.sub(str, 1 + math.max(0, dx - (w - offset))))
  785.       elseif ncx < 1 + offset then
  786.         local sx = nbx - 1
  787.         local dx = math.abs(scrollX - sx)
  788.         scrollX = sx
  789.         component.gpu.copy(1 + offset, cy, w - offset - dx, 1, dx, 0)
  790.         local str = unicode.sub(history[nby], nbx, nbx + dx)
  791.         --str = text.padRight(str, dx)
  792.         component.gpu.set(1 + offset, cy, str)
  793.       end
  794.  
  795.       term.setCursor(nbx - scrollX + offset, cy)
  796.     end
  797.  
  798.     local function copyIfNecessary()
  799.       local cbx, cby = getCursor()
  800.       if cby ~= #history then
  801.         history[#history] = line()
  802.         setCursor(cbx, #history)
  803.       end
  804.     end
  805.  
  806.     local function redraw()
  807.       local cx, cy = term.getCursor()
  808.       local bx, by = 1 + scrollX, 1 + scrollY
  809.       local w, h = component.gpu.getResolution()
  810.       local l = w - offset
  811.       local str = unicode.sub(history[by], bx, bx + l)
  812.       str = text.padRight(str, l)
  813.       component.gpu.set(1 + offset, cy, str)
  814.     end
  815.  
  816.     local function home()
  817.       local cbx, cby = getCursor()
  818.       setCursor(1, cby)
  819.     end
  820.  
  821.     local function ende()
  822.       local cbx, cby = getCursor()
  823.       setCursor(unicode.len(line()) + 1, cby)
  824.     end
  825.  
  826.     local function left()
  827.       local cbx, cby = getCursor()
  828.       if cbx > 1 then
  829.         setCursor(cbx - 1, cby)
  830.         return true -- for backspace
  831.       end
  832.     end
  833.  
  834.     local function right(n)
  835.       n = n or 1
  836.       local cbx, cby = getCursor()
  837.       local be = unicode.len(line()) + 1
  838.       if cbx < be then
  839.         setCursor(math.min(be, cbx + n), cby)
  840.       end
  841.     end
  842.  
  843.     local function up()
  844.       local cbx, cby = getCursor()
  845.       if cby > 1 then
  846.         setCursor(1, cby - 1)
  847.         redraw()
  848.         ende()
  849.       end
  850.     end
  851.  
  852.     local function down()
  853.       local cbx, cby = getCursor()
  854.       if cby < #history then
  855.         setCursor(1, cby + 1)
  856.         redraw()
  857.         ende()
  858.       end
  859.     end
  860.  
  861.     local function delete()
  862.       copyIfNecessary()
  863.       local cbx, cby = getCursor()
  864.       if cbx <= unicode.len(line()) then
  865.         history[cby] = unicode.sub(line(), 1, cbx - 1) ..
  866.                        unicode.sub(line(), cbx + 1)
  867.         local cx, cy = term.getCursor()
  868.         local w, h = component.gpu.getResolution()
  869.         component.gpu.copy(cx + 1, cy, w - cx, 1, -1, 0)
  870.         local br = cbx + (w - cx)
  871.         local char = unicode.sub(line(), br, br)
  872.         if not char or unicode.len(char) == 0 then
  873.           char = " "
  874.         end
  875.         component.gpu.set(w, cy, char)
  876.       end
  877.     end
  878.  
  879.     local function insert(value)
  880.       copyIfNecessary()
  881.       local cx, cy = term.getCursor()
  882.       local cbx, cby = getCursor()
  883.       local w, h = component.gpu.getResolution()
  884.       history[cby] = unicode.sub(line(), 1, cbx - 1) ..
  885.                      value ..
  886.                      unicode.sub(line(), cbx)
  887.       local len = unicode.len(value)
  888.       local n = w - (cx - 1) - len
  889.       if n > 0 then
  890.         component.gpu.copy(cx, cy, n, 1, len, 0)
  891.       end
  892.       component.gpu.set(cx, cy, value)
  893.       right(len)
  894.     end
  895.  
  896.     local function onKeyDown(char, code)
  897.       term.setCursorBlink(false)
  898.       if code == keyboard.keys.back then
  899.         if left() then delete() end
  900.       elseif code == keyboard.keys.delete then
  901.         delete()
  902.       elseif code == keyboard.keys.left then
  903.         left()
  904.       elseif code == keyboard.keys.right then
  905.         right()
  906.       elseif code == keyboard.keys.home then
  907.         home()
  908.       elseif code == keyboard.keys["end"] then
  909.         ende()
  910.       elseif code == keyboard.keys.up then
  911.         up()
  912.       elseif code == keyboard.keys.down then
  913.         down()
  914.       elseif code == keyboard.keys.enter then
  915.         local cbx, cby = getCursor()
  916.         if cby ~= #history then -- bring entry to front
  917.           history[#history] = line()
  918.           table.remove(history, cby)
  919.         end
  920.         return true, history[#history] .. "\n"
  921.       elseif keyboard.isControlDown() and code == keyboard.keys.d then
  922.         if line() == "" then
  923.           history[#history] = ""
  924.           return true, nil
  925.         end
  926.       elseif keyboard.isControlDown() and code == keyboard.keys.c then
  927.         history[#history] = ""
  928.         return true, nil
  929.       elseif not keyboard.isControl(char) then
  930.         insert(unicode.char(char))
  931.       end
  932.       term.setCursorBlink(true)
  933.       term.setCursorBlink(true) -- force toggle to caret
  934.     end
  935.  
  936.     local function onClipboard(value)
  937.       copyIfNecessary()
  938.       term.setCursorBlink(false)
  939.       local cbx, cby = getCursor()
  940.       local l = value:find("\n", 1, true)
  941.       if l then
  942.         history[cby] = unicode.sub(line(), 1, cbx - 1)
  943.         redraw()
  944.         insert(unicode.sub(value, 1, l - 1))
  945.         return true, line() .. "\n"
  946.       else
  947.         insert(value)
  948.         term.setCursorBlink(true)
  949.         term.setCursorBlink(true) -- force toggle to caret
  950.       end
  951.     end
  952.  
  953.     local function cleanup()
  954.       if history[#history] == "" then
  955.         table.remove(history)
  956.       end
  957.       term.setCursorBlink(false)
  958.       if term.getCursor() > 1 and dobreak ~= false then
  959.         print()
  960.       end
  961.     end
  962.  
  963.     term.setCursorBlink(true)
  964.     while term.isAvailable() do
  965.       local ocx, ocy = getCursor()
  966.       local ok, name, address, charOrValue, code = pcall(event.pull)
  967.       if not ok then
  968.         cleanup()
  969.         error("interrupted", 0)
  970.       end
  971.       local ncx, ncy = getCursor()
  972.       if ocx ~= ncx or ocy ~= ncy then
  973.         cleanup()
  974.         return "" -- soft fail the read if someone messes with the term
  975.       end
  976.       if term.isAvailable() and -- may have changed since pull
  977.          type(address) == "string" and
  978.          component.isPrimary(address)
  979.       then
  980.         local done, result
  981.         if name == "key_down" then
  982.           done, result = onKeyDown(charOrValue, code)
  983.         elseif name == "clipboard" then
  984.           done, result = onClipboard(charOrValue)
  985.         end
  986.         if done then
  987.           cleanup()
  988.           return result
  989.         end
  990.       end
  991.     end
  992.     cleanup()
  993.     return nil -- fail the read if term becomes unavailable
  994.   end
  995.  
  996.   function term.write(value, wrap)
  997.     if not term.isAvailable() then
  998.       return
  999.     end
  1000.     value = tostring(value)
  1001.     if unicode.len(value) == 0 then
  1002.       return
  1003.     end
  1004.     do
  1005.       local noBell = value:gsub("\a", "")
  1006.       if #noBell ~= #value then
  1007.         value = noBell
  1008.         computer.beep()
  1009.       end
  1010.     end
  1011.     value = text.detab(value)
  1012.     local w, h = component.gpu.getResolution()
  1013.     if not w then
  1014.       return -- gpu lost its screen but the signal wasn't processed yet.
  1015.     end
  1016.     local blink = term.getCursorBlink()
  1017.     term.setCursorBlink(false)
  1018.     local line, nl
  1019.     repeat
  1020.       local wrapAfter, margin = math.huge, math.huge
  1021.       if wrap then
  1022.         wrapAfter, margin = w - (cursorX - 1), w
  1023.       end
  1024.       line, value, nl = text.wrap(value, wrapAfter, margin)
  1025.       component.gpu.set(cursorX, cursorY, line)
  1026.       cursorX = cursorX + unicode.len(line)
  1027.       if nl or (cursorX > w and wrap) then
  1028.         cursorX = 1
  1029.         cursorY = cursorY + 1
  1030.       end
  1031.       if cursorY > h then
  1032.         component.gpu.copy(1, 1, w, h, 0, -1)
  1033.         component.gpu.fill(1, h, w, 1, " ")
  1034.         cursorY = h
  1035.       end
  1036.     until not value
  1037.     term.setCursorBlink(blink)
  1038.   end
  1039.  
  1040.   -------------------------------------------------------------------------------
  1041.  
  1042.   return term
  1043. end
  1044.  
  1045. function keyboard_code(keyboard_data)
  1046.   local keyboard = {pressedChars = {}, pressedCodes = {}, keys = keyboard_data.keys}
  1047.  
  1048.   -- Create inverse mapping for name lookup.
  1049.   setmetatable(keyboard.keys, {
  1050.     __index = function(tbl, k)
  1051.       if type(k) ~= "number" then return end
  1052.       for name,value in pairs(tbl) do
  1053.         if value == k then
  1054.           return name
  1055.         end
  1056.       end
  1057.     end
  1058.   })
  1059.  
  1060.   local function getKeyboardAddress(address)
  1061.     return address or term.keyboard().address
  1062.   end
  1063.  
  1064.   local function getPressedCodes(address)
  1065.     address = getKeyboardAddress(address)
  1066.     return address and keyboard.pressedCodes[address] or false
  1067.   end
  1068.  
  1069.   local function getPressedChars(address)
  1070.     address = getKeyboardAddress(address)
  1071.     return address and keyboard.pressedChars[address] or false
  1072.   end
  1073.  
  1074.   function keyboard.isAltDown(address)
  1075.     checkArg(1, address, "string", "nil")
  1076.     local pressedCodes = getPressedCodes(address)
  1077.     return pressedCodes and (pressedCodes[keyboard.keys.lmenu] or pressedCodes[keyboard.keys.rmenu]) ~= nil
  1078.   end
  1079.  
  1080.   function keyboard.isControl(char)
  1081.     return type(char) == "number" and (char < 0x20 or (char >= 0x7F and char <= 0x9F))
  1082.   end
  1083.  
  1084.   function keyboard.isControlDown(address)
  1085.     checkArg(1, address, "string", "nil")
  1086.     local pressedCodes = getPressedCodes(address)
  1087.     return pressedCodes and (pressedCodes[keyboard.keys.lcontrol] or pressedCodes[keyboard.keys.rcontrol]) ~= nil
  1088.   end
  1089.  
  1090.   function keyboard.isKeyDown(charOrCode, address)
  1091.     checkArg(1, charOrCode, "string", "number")
  1092.     checkArg(2, address, "string", "nil")
  1093.     if type(charOrCode) == "string" then
  1094.       local pressedChars = getPressedChars(address)
  1095.       return pressedChars and pressedChars[utf8 and utf8.codepoint(charOrCode) or charOrCode:byte()]
  1096.     elseif type(charOrCode) == "number" then
  1097.       local pressedCodes = getPressedCodes(address)
  1098.       return pressedCodes and pressedCodes[charOrCode]
  1099.     end
  1100.   end
  1101.  
  1102.   function keyboard.isShiftDown(address)
  1103.     checkArg(1, address, "string", "nil")
  1104.     local pressedCodes = getPressedCodes(address)
  1105.     return pressedCodes and (pressedCodes[keyboard.keys.lshift] or pressedCodes[keyboard.keys.rshift]) ~= nil
  1106.   end
  1107.  
  1108.   local function onKeyDown(_, address, char, code)
  1109.     if keyboard.pressedChars[address] then
  1110.       keyboard.pressedChars[address][char] = true
  1111.       keyboard.pressedCodes[address][code] = true
  1112.     end
  1113.   end
  1114.  
  1115.   local function onKeyUp(_, address, char, code)
  1116.     if keyboard.pressedChars[address] then
  1117.       keyboard.pressedChars[address][char] = nil
  1118.       keyboard.pressedCodes[address][code] = nil
  1119.     end
  1120.   end
  1121.  
  1122.   local function onComponentAdded(_, address, componentType)
  1123.     if componentType == "keyboard" then
  1124.       keyboard.pressedChars[address] = {}
  1125.       keyboard.pressedCodes[address] = {}
  1126.     end
  1127.   end
  1128.  
  1129.   local function onComponentRemoved(_, address, componentType)
  1130.     if componentType == "keyboard" then
  1131.       keyboard.pressedChars[address] = nil
  1132.       keyboard.pressedCodes[address] = nil
  1133.     end
  1134.   end
  1135.  
  1136.   for address in component.list("keyboard", true) do
  1137.     onComponentAdded("component_added", address, "keyboard")
  1138.   end
  1139.  
  1140.   event.listen("key_down", onKeyDown)
  1141.   event.listen("key_up", onKeyUp)
  1142.   event.listen("component_added", onComponentAdded)
  1143.   event.listen("component_removed", onComponentRemoved)
  1144.  
  1145.   return keyboard
  1146. end
  1147.  
  1148. local function printProcess(...)
  1149.   local args = table.pack(...)
  1150.   local argstr = ""
  1151.   for i = 1, args.n do
  1152.     local arg = tostring(args[i])
  1153.     if i > 1 then
  1154.       arg = "\t" .. arg
  1155.     end
  1156.     argstr = argstr .. arg
  1157.   end
  1158.   return argstr
  1159. end
  1160. function print(...)
  1161.   term.write(printProcess(...) .. "\n", true)
  1162. end
  1163. function printErr(...)
  1164.         local c = component.gpu.getForeground()
  1165.         component.gpu.setForeground(0xFF0000)
  1166.         print(...)
  1167.         component.gpu.setForeground(c)
  1168. end
  1169. function printPaged(...)
  1170.   argstr = printProcess(...) .. "\n"
  1171.   local i = 0
  1172.   local p = 0
  1173.   function readline()
  1174.     i = string.find(argstr, "\n", i+1)    -- find 'next' newline
  1175.     if i == nil then return nil end
  1176.     local out = argstr:sub(p,i)
  1177.     p = i + 1
  1178.     return out
  1179.   end
  1180.   local function readlines(file, line, num)
  1181.     local w, h = component.gpu.getResolution()
  1182.     num = num or (h - 1)
  1183.     --num = num or (h)
  1184.     term.setCursorBlink(false)
  1185.     for _ = 1, num do
  1186.       if not line then
  1187.         line = readline()
  1188.         if not line then -- eof
  1189.           return nil
  1190.         end
  1191.       end
  1192.       local wrapped
  1193.       wrapped, line = text.wrap(text.detab(line), w, w)
  1194.       term.write(wrapped .. "\n")
  1195.     end
  1196.     term.setCursor(1, h)
  1197.     term.write("Press enter or space to continue:")
  1198.     term.setCursorBlink(true)
  1199.     return true
  1200.   end
  1201.  
  1202.   local line = nil
  1203.   while true do
  1204.     if not readlines(file, line) then
  1205.       return
  1206.     end
  1207.     while true do
  1208.       local event, address, char, code = event.pull("key_down")
  1209.       if component.isPrimary(address) then
  1210.         if code == keyboard.keys.q then
  1211.           term.setCursorBlink(false)
  1212.           term.clearLine()
  1213.           return
  1214.         elseif code == keyboard.keys.space or code == keyboard.keys.pageDown then
  1215.           term.clearLine()
  1216.           break
  1217.         elseif code == keyboard.keys.enter or code == keyboard.keys.down then
  1218.           term.clearLine()
  1219.           if not readlines(file, line, 1) then
  1220.             return
  1221.           end
  1222.         end
  1223.       end
  1224.     end
  1225.   end
  1226. end
  1227. --load programs
  1228. function loadfile(file, mode, env)
  1229.   local handle, reason = filesystem.open(file)
  1230.   if not handle then
  1231.     error(reason, 2)
  1232.   end
  1233.   local buffer = ""
  1234.   repeat
  1235.     local data, reason = filesystem.read(handle)
  1236.     if not data and reason then
  1237.       error(reason)
  1238.     end
  1239.     buffer = buffer .. (data or "")
  1240.   until not data
  1241.   filesystem.close(handle)
  1242.   if mode == nil then mode = "bt" end
  1243.   if env == nil then env = _G end
  1244.   return load(buffer, "=" .. file)
  1245. end
  1246.  
  1247. function dofile(file)
  1248.   local program, reason = loadfile(file)
  1249.   if program then
  1250.     local result = table.pack(pcall(program))
  1251.     if result[1] then
  1252.       return table.unpack(result, 2, result.n)
  1253.     else
  1254.       error(result[2])
  1255.     end
  1256.   else
  1257.     error(reason)
  1258.   end
  1259. end
  1260.  
  1261. --set up libs
  1262. event = event_code()
  1263. component_code()
  1264. text = text_code()
  1265. filesystem = fs_code()
  1266. fs = filesystem
  1267. keyboard = keyboard_code(dofile("keyboard.lua"))
  1268. term = terminal_code()
  1269.  
  1270. -- set up other functions...
  1271. os.sleep = function(timeout)
  1272.   checkArg(1, timeout, "number", "nil")
  1273.   local deadline = computer.uptime() + (timeout or 0)
  1274.   repeat
  1275.     event.pull(deadline - computer.uptime())
  1276.   until computer.uptime() >= deadline
  1277. end
  1278.  
  1279. os.exit = function(code)
  1280.   error({[1]="INTERRUPT", [2]="EXIT", [3]=code})
  1281. end
  1282.  
  1283. --set up terminal
  1284. if term.isAvailable() then
  1285.   component.gpu.bind(component.screen.address)
  1286.   component.gpu.setResolution(component.gpu.getResolution())
  1287.   component.gpu.setBackground(0x000000)
  1288.   component.gpu.setForeground(0xFFFFFF)
  1289.   term.setCursorBlink(true)
  1290.   term.clear()
  1291. end
  1292.  
  1293. print("Starting " .. _OSNAME .. "...\n")
  1294. print(_OSCREDIT .. "\n")
  1295.  
  1296. --clean up libs
  1297. event_code, component_code, text_code, fs_code, terminal_code, keyboard_code = nil, nil, nil, nil, nil, nil
  1298.  
  1299. --map the drives
  1300. for address, componentType in component.list() do
  1301.   if componentType == "filesystem" then filesystem.drive.autoMap(address) end
  1302. end
  1303.  
  1304. miniOS = {}
  1305. local function interrupt(data)
  1306.   --print("INTERRUPT!")
  1307.   if data[2] == "RUN" then return miniOS.runfile(data[3], table.unpack(data[4])) end
  1308.   if data[2] == "ERR" then error("This error is for testing!") end
  1309.   if data[2] == "EXIT" then return data[3] end
  1310. end
  1311. local function runfile(file, ...)
  1312.   local program, reason = loadfile(file)
  1313.   if program then
  1314.     local targs = {...}
  1315.     local traceback
  1316.     local result = table.pack(xpcall(program,
  1317.       function(err) traceback = debug.traceback(nil, 2); return err end,
  1318.       ...))
  1319.     --local result = table.pack(pcall(program, ...))
  1320.     if traceback then
  1321.         local function dropsame(s1,s2)
  1322.             t1,t2={},{}
  1323.             for l in s1:gmatch("(.-)\n") do t1[#t1+1] = l end
  1324.             for l in s2:gmatch("(.-)\n") do t2[#t2+1] = l end
  1325.             for i = #t1,1,-1 do
  1326.                 if t1[i] == t2[i] then
  1327.                     t1[i] = nil
  1328.                     t2[i] = nil
  1329.                 else
  1330.                     break
  1331.                 end
  1332.             end
  1333.             os1,os2 = "",""
  1334.             for k,v in ipairs(t1) do
  1335.                 os1 = os1 .. v .. "\n"
  1336.             end
  1337.             for k,v in ipairs(t2) do
  1338.                 os2 = os2 .. v .. "\n"
  1339.             end
  1340.             return os1,os2
  1341.         end
  1342.       traceback = dropsame(traceback, debug.traceback(nil, 2)) .. "\t..."
  1343.     end
  1344.     if result[1] then
  1345.       return table.unpack(result, 2, result.n)
  1346.     else
  1347.       if type(result[2]) == "table" then if result[2][1] then if result[2][1] == "INTERRUPT" then
  1348.         result = {interrupt(result[2])}
  1349.         --if not result[1] then
  1350.           --error(result[2], 3)
  1351.         --else
  1352.           --return table.unpack(result, 2, result.n)
  1353.         --end
  1354.         return
  1355.       end end end
  1356.       error(result[2] .. "\n" .. traceback, 3)
  1357.     end
  1358.   else
  1359.     error(reason, 3)
  1360.   end
  1361. end
  1362. local function kernelError()
  1363.   printErr("\nPress any key to try again.")
  1364.   term.readKey()
  1365. end
  1366. function miniOS.saferunfile(...)
  1367.   local r = {pcall(runfile, ...)}
  1368.   if not r[1] then
  1369.     local c = component.gpu.getForeground()
  1370.     component.gpu.setForeground(0xFF0000)
  1371.     printPaged(r[2])
  1372.     component.gpu.setForeground(c)
  1373.   end
  1374.   return r
  1375. end
  1376. function miniOS.runfile(...)
  1377.  local r = miniOS.saferunfile(...)
  1378.  return table.unpack(r, 2, r.n)
  1379. end
  1380.  
  1381. local function tryrunlib(lib)
  1382.     local ret
  1383.     local opt = {lib .. ".lua", lib}
  1384.     for _,o in ipairs(opt) do
  1385.         if fs.exists(o) then
  1386.             return miniOS.runfile(o)
  1387.         end
  1388.     end
  1389.     error("Can't find the library specified: `" .. lib .. "`", 3)
  1390. end
  1391. function require(lib)
  1392.     return _G[lib] or _G[string.lower(lib)] or tryrunlib(lib)
  1393. end
  1394. local function shellrun(...)
  1395.     local success = miniOS.saferunfile(...)[1]
  1396.     if not success then
  1397.         printErr("\n\nError in running command interpreter.")
  1398.         return false
  1399.     end
  1400.     return true
  1401. end
  1402.  
  1403. miniOS.freeMem = computer.freeMemory()
  1404.  
  1405. --start command and keep it running.
  1406. local fallback_drive = fs.drive.getcurrent()
  1407. if filesystem.exists("autoexec.bat") then shellrun("command.lua", "autoexec.bat") else shellrun("command.lua") end
  1408. while true do
  1409.     miniOS.freeMem = computer.freeMemory()
  1410.     print()
  1411.     fs.drive.setcurrent(fallback_drive)
  1412.     if not shellrun("command.lua", "-c") then printErr("Will restart command interpreter..."); kernelError() end
  1413. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement