osmarks

Tetrahedron BIOS

Dec 14th, 2019
261
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. function loadstring(code, env)
  2.     local e = _G
  3.     local name = "@code"
  4.     if type(env) == "table" then e = env
  5.     elseif type(env) == "string" then name = env end
  6.     return load(code, name, "t", e)
  7. end
  8.  
  9. -- Load in expect from the module path.
  10. --
  11. -- Ideally we'd use require, but that is part of the shell, and so is not
  12. -- available to the BIOS or any APIs. All APIs load this using dofile, but that
  13. -- has not been defined at this point.
  14. local expect
  15.  
  16. do
  17.     local h = fs.open("rom/modules/main/cc/expect.lua", "r")
  18.     local f, err = loadstring(h.readAll(), "@expect.lua")
  19.     h.close()
  20.  
  21.     if not f then error(err) end
  22.     expect = f().expect
  23. end
  24.  
  25. if _VERSION == "Lua 5.1" then
  26.     -- If we're on Lua 5.1, install parts of the Lua 5.2/5.3 API so that programs can be written against it
  27.     local type = type
  28.     local nativeload = load
  29.     local nativeloadstring = loadstring
  30.     local nativesetfenv = setfenv
  31.  
  32.     --- Historically load/loadstring would handle the chunk name as if it has
  33.     -- been prefixed with "=". We emulate that behaviour here.
  34.     local function prefix(chunkname)
  35.         if type(chunkname) ~= "string" then return chunkname end
  36.         local head = chunkname:sub(1, 1)
  37.         if head == "=" or head == "@" then
  38.             return chunkname
  39.         else
  40.             return "=" .. chunkname
  41.         end
  42.     end
  43.  
  44.     function load( x, name, mode, env )
  45.         expect(1, x, "function", "string")
  46.         expect(2, name, "string", "nil")
  47.         expect(3, mode, "string", "nil")
  48.         expect(4, env, "table", "nil")
  49.  
  50.         local ok, p1, p2 = pcall( function()
  51.             if type(x) == "string" then
  52.                 local result, err = nativeloadstring( x, name )
  53.                 if result then
  54.                     if env then
  55.                         env._ENV = env
  56.                         nativesetfenv( result, env )
  57.                     end
  58.                     return result
  59.                 else
  60.                     return nil, err
  61.                 end
  62.             else
  63.                 local result, err = nativeload( x, name )
  64.                 if result then
  65.                     if env then
  66.                         env._ENV = env
  67.                         nativesetfenv( result, env )
  68.                     end
  69.                     return result
  70.                 else
  71.                     return nil, err
  72.                 end
  73.             end
  74.         end )
  75.         if ok then
  76.             return p1, p2
  77.         else
  78.             error( p1, 2 )
  79.         end
  80.     end
  81.     table.unpack = unpack
  82.     table.pack = function( ... ) return { n = select( "#", ... ), ... } end
  83.  
  84.     if _CC_DISABLE_LUA51_FEATURES then
  85.         -- Remove the Lua 5.1 features that will be removed when we update to Lua 5.2, for compatibility testing.
  86.         -- See "disable_lua51_functions" in ComputerCraft.cfg
  87.         setfenv = nil
  88.         getfenv = nil
  89.         loadstring = nil
  90.         unpack = nil
  91.         math.log10 = nil
  92.         table.maxn = nil
  93.     else
  94.         loadstring = function(string, chunkname) return nativeloadstring(string, prefix( chunkname )) end
  95.  
  96.         -- Inject a stub for the old bit library
  97.         _G.bit = {
  98.             bnot = bit32.bnot,
  99.             band = bit32.band,
  100.             bor = bit32.bor,
  101.             bxor = bit32.bxor,
  102.             brshift = bit32.arshift,
  103.             blshift = bit32.lshift,
  104.             blogic_rshift = bit32.rshift,
  105.         }
  106.     end
  107. end
  108.  
  109. if _VERSION == "Lua 5.3" and not bit32 then
  110.     -- If we're on Lua 5.3, install the bit32 api from Lua 5.2
  111.     -- (Loaded from a string so this file will still parse on <5.3 lua)
  112.     load( [[
  113.         bit32 = {}
  114.  
  115.         function bit32.arshift( n, bits )
  116.             if type(n) ~= "number" or type(bits) ~= "number" then
  117.                 error( "Expected number, number", 2 )
  118.             end
  119.             return n >> bits
  120.         end
  121.  
  122.         function bit32.band( m, n )
  123.             if type(m) ~= "number" or type(n) ~= "number" then
  124.                 error( "Expected number, number", 2 )
  125.             end
  126.             return m & n
  127.         end
  128.  
  129.         function bit32.bnot( n )
  130.             if type(n) ~= "number" then
  131.                 error( "Expected number", 2 )
  132.             end
  133.             return ~n
  134.         end
  135.  
  136.         function bit32.bor( m, n )
  137.             if type(m) ~= "number" or type(n) ~= "number" then
  138.                 error( "Expected number, number", 2 )
  139.             end
  140.             return m | n
  141.         end
  142.  
  143.         function bit32.btest( m, n )
  144.             if type(m) ~= "number" or type(n) ~= "number" then
  145.                 error( "Expected number, number", 2 )
  146.             end
  147.             return (m & n) ~= 0
  148.         end
  149.  
  150.         function bit32.bxor( m, n )
  151.             if type(m) ~= "number" or type(n) ~= "number" then
  152.                 error( "Expected number, number", 2 )
  153.             end
  154.             return m ~ n
  155.         end
  156.  
  157.         function bit32.lshift( n, bits )
  158.             if type(n) ~= "number" or type(bits) ~= "number" then
  159.                 error( "Expected number, number", 2 )
  160.             end
  161.             return n << bits
  162.         end
  163.  
  164.         function bit32.rshift( n, bits )
  165.             if type(n) ~= "number" or type(bits) ~= "number" then
  166.                 error( "Expected number, number", 2 )
  167.             end
  168.             return n >> bits
  169.         end
  170.     ]] )()
  171. end
  172.  
  173. -- Install lua parts of the os api
  174. function os.version()
  175.     return "CraftOS 1.8"
  176. end
  177.  
  178. function os.pullEventRaw( sFilter )
  179.     return coroutine.yield( sFilter )
  180. end
  181.  
  182. function os.pullEvent( sFilter )
  183.     local eventData = table.pack( os.pullEventRaw( sFilter ) )
  184.     if eventData[1] == "terminate" then
  185.         error( "Terminated", 0 )
  186.     end
  187.     return table.unpack( eventData, 1, eventData.n )
  188. end
  189.  
  190. -- Install globals
  191. function sleep( nTime )
  192.     expect(1, nTime, "number", "nil")
  193.     local timer = os.startTimer( nTime or 0 )
  194.     repeat
  195.         local _, param = os.pullEvent( "timer" )
  196.     until param == timer
  197. end
  198.  
  199. function write( sText )
  200.     expect(1, sText, "string", "number")
  201.  
  202.     local w, h = term.getSize()
  203.     local x, y = term.getCursorPos()
  204.  
  205.     local nLinesPrinted = 0
  206.     local function newLine()
  207.         if y + 1 <= h then
  208.             term.setCursorPos(1, y + 1)
  209.         else
  210.             term.setCursorPos(1, h)
  211.             term.scroll(1)
  212.         end
  213.         x, y = term.getCursorPos()
  214.         nLinesPrinted = nLinesPrinted + 1
  215.     end
  216.  
  217.     -- Print the line with proper word wrapping
  218.     while #sText > 0 do
  219.         local whitespace = string.match( sText, "^[ \t]+" )
  220.         if whitespace then
  221.             -- Print whitespace
  222.             term.write( whitespace )
  223.             x, y = term.getCursorPos()
  224.             sText = string.sub( sText, #whitespace + 1 )
  225.         end
  226.  
  227.         local newline = string.match( sText, "^\n" )
  228.         if newline then
  229.             -- Print newlines
  230.             newLine()
  231.             sText = string.sub( sText, 2 )
  232.         end
  233.  
  234.         local text = string.match( sText, "^[^ \t\n]+" )
  235.         if text then
  236.             sText = string.sub( sText, #text + 1 )
  237.             if #text > w then
  238.                 -- Print a multiline word
  239.                 while #text > 0 do
  240.                     if x > w then
  241.                         newLine()
  242.                     end
  243.                     term.write( text )
  244.                     text = string.sub( text, w - x + 2 )
  245.                     x, y = term.getCursorPos()
  246.                 end
  247.             else
  248.                 -- Print a word normally
  249.                 if x + #text - 1 > w then
  250.                     newLine()
  251.                 end
  252.                 term.write( text )
  253.                 x, y = term.getCursorPos()
  254.             end
  255.         end
  256.     end
  257.  
  258.     return nLinesPrinted
  259. end
  260.  
  261. function print( ... )
  262.     local nLinesPrinted = 0
  263.     local nLimit = select("#", ... )
  264.     for n = 1, nLimit do
  265.         local s = tostring( select( n, ... ) )
  266.         if n < nLimit then
  267.             s = s .. "\t"
  268.         end
  269.         nLinesPrinted = nLinesPrinted + write( s )
  270.     end
  271.     nLinesPrinted = nLinesPrinted + write( "\n" )
  272.     return nLinesPrinted
  273. end
  274.  
  275. function printError( ... )
  276.     local oldColour
  277.     if term.isColour() then
  278.         oldColour = term.getTextColour()
  279.         term.setTextColour( colors.red )
  280.     end
  281.     print( ... )
  282.     if term.isColour() then
  283.         term.setTextColour( oldColour )
  284.     end
  285. end
  286.  
  287. function read( _sReplaceChar, _tHistory, _fnComplete, _sDefault )
  288.     expect(1, _sReplaceChar, "string", "nil")
  289.     expect(2, _tHistory, "table", "nil")
  290.     expect(3, _fnComplete, "function", "nil")
  291.     expect(4, _sDefault, "string", "nil")
  292.  
  293.     term.setCursorBlink( true )
  294.  
  295.     local sLine
  296.     if type( _sDefault ) == "string" then
  297.         sLine = _sDefault
  298.     else
  299.         sLine = ""
  300.     end
  301.     local nHistoryPos
  302.     local nPos, nScroll = #sLine, 0
  303.     if _sReplaceChar then
  304.         _sReplaceChar = string.sub( _sReplaceChar, 1, 1 )
  305.     end
  306.  
  307.     local tCompletions
  308.     local nCompletion
  309.     local function recomplete()
  310.         if _fnComplete and nPos == #sLine then
  311.             tCompletions = _fnComplete( sLine )
  312.             if tCompletions and #tCompletions > 0 then
  313.                 nCompletion = 1
  314.             else
  315.                 nCompletion = nil
  316.             end
  317.         else
  318.             tCompletions = nil
  319.             nCompletion = nil
  320.         end
  321.     end
  322.  
  323.     local function uncomplete()
  324.         tCompletions = nil
  325.         nCompletion = nil
  326.     end
  327.  
  328.     local w = term.getSize()
  329.     local sx = term.getCursorPos()
  330.  
  331.     local function redraw( _bClear )
  332.         local cursor_pos = nPos - nScroll
  333.         if sx + cursor_pos >= w then
  334.             -- We've moved beyond the RHS, ensure we're on the edge.
  335.             nScroll = sx + nPos - w
  336.         elseif cursor_pos < 0 then
  337.             -- We've moved beyond the LHS, ensure we're on the edge.
  338.             nScroll = nPos
  339.         end
  340.  
  341.         local _, cy = term.getCursorPos()
  342.         term.setCursorPos( sx, cy )
  343.         local sReplace = _bClear and " " or _sReplaceChar
  344.         if sReplace then
  345.             term.write( string.rep( sReplace, math.max( #sLine - nScroll, 0 ) ) )
  346.         else
  347.             term.write( string.sub( sLine, nScroll + 1 ) )
  348.         end
  349.  
  350.         if nCompletion then
  351.             local sCompletion = tCompletions[ nCompletion ]
  352.             local oldText, oldBg
  353.             if not _bClear then
  354.                 oldText = term.getTextColor()
  355.                 oldBg = term.getBackgroundColor()
  356.                 term.setTextColor( colors.white )
  357.                 term.setBackgroundColor( colors.gray )
  358.             end
  359.             if sReplace then
  360.                 term.write( string.rep( sReplace, #sCompletion ) )
  361.             else
  362.                 term.write( sCompletion )
  363.             end
  364.             if not _bClear then
  365.                 term.setTextColor( oldText )
  366.                 term.setBackgroundColor( oldBg )
  367.             end
  368.         end
  369.  
  370.         term.setCursorPos( sx + nPos - nScroll, cy )
  371.     end
  372.  
  373.     local function clear()
  374.         redraw( true )
  375.     end
  376.  
  377.     recomplete()
  378.     redraw()
  379.  
  380.     local function acceptCompletion()
  381.         if nCompletion then
  382.             -- Clear
  383.             clear()
  384.  
  385.             -- Find the common prefix of all the other suggestions which start with the same letter as the current one
  386.             local sCompletion = tCompletions[ nCompletion ]
  387.             sLine = sLine .. sCompletion
  388.             nPos = #sLine
  389.  
  390.             -- Redraw
  391.             recomplete()
  392.             redraw()
  393.         end
  394.     end
  395.     while true do
  396.         local sEvent, param, param1, param2 = os.pullEvent()
  397.         if sEvent == "char" then
  398.             -- Typed key
  399.             clear()
  400.             sLine = string.sub( sLine, 1, nPos ) .. param .. string.sub( sLine, nPos + 1 )
  401.             nPos = nPos + 1
  402.             recomplete()
  403.             redraw()
  404.  
  405.         elseif sEvent == "paste" then
  406.             -- Pasted text
  407.             clear()
  408.             sLine = string.sub( sLine, 1, nPos ) .. param .. string.sub( sLine, nPos + 1 )
  409.             nPos = nPos + #param
  410.             recomplete()
  411.             redraw()
  412.  
  413.         elseif sEvent == "key" then
  414.             if param == keys.enter then
  415.                 -- Enter
  416.                 if nCompletion then
  417.                     clear()
  418.                     uncomplete()
  419.                     redraw()
  420.                 end
  421.                 break
  422.  
  423.             elseif param == keys.left then
  424.                 -- Left
  425.                 if nPos > 0 then
  426.                     clear()
  427.                     nPos = nPos - 1
  428.                     recomplete()
  429.                     redraw()
  430.                 end
  431.  
  432.             elseif param == keys.right then
  433.                 -- Right
  434.                 if nPos < #sLine then
  435.                     -- Move right
  436.                     clear()
  437.                     nPos = nPos + 1
  438.                     recomplete()
  439.                     redraw()
  440.                 else
  441.                     -- Accept autocomplete
  442.                     acceptCompletion()
  443.                 end
  444.  
  445.             elseif param == keys.up or param == keys.down then
  446.                 -- Up or down
  447.                 if nCompletion then
  448.                     -- Cycle completions
  449.                     clear()
  450.                     if param == keys.up then
  451.                         nCompletion = nCompletion - 1
  452.                         if nCompletion < 1 then
  453.                             nCompletion = #tCompletions
  454.                         end
  455.                     elseif param == keys.down then
  456.                         nCompletion = nCompletion + 1
  457.                         if nCompletion > #tCompletions then
  458.                             nCompletion = 1
  459.                         end
  460.                     end
  461.                     redraw()
  462.  
  463.                 elseif _tHistory then
  464.                     -- Cycle history
  465.                     clear()
  466.                     if param == keys.up then
  467.                         -- Up
  468.                         if nHistoryPos == nil then
  469.                             if #_tHistory > 0 then
  470.                                 nHistoryPos = #_tHistory
  471.                             end
  472.                         elseif nHistoryPos > 1 then
  473.                             nHistoryPos = nHistoryPos - 1
  474.                         end
  475.                     else
  476.                         -- Down
  477.                         if nHistoryPos == #_tHistory then
  478.                             nHistoryPos = nil
  479.                         elseif nHistoryPos ~= nil then
  480.                             nHistoryPos = nHistoryPos + 1
  481.                         end
  482.                     end
  483.                     if nHistoryPos then
  484.                         sLine = _tHistory[nHistoryPos]
  485.                         nPos, nScroll = #sLine, 0
  486.                     else
  487.                         sLine = ""
  488.                         nPos, nScroll = 0, 0
  489.                     end
  490.                     uncomplete()
  491.                     redraw()
  492.  
  493.                 end
  494.  
  495.             elseif param == keys.backspace then
  496.                 -- Backspace
  497.                 if nPos > 0 then
  498.                     clear()
  499.                     sLine = string.sub( sLine, 1, nPos - 1 ) .. string.sub( sLine, nPos + 1 )
  500.                     nPos = nPos - 1
  501.                     if nScroll > 0 then nScroll = nScroll - 1 end
  502.                     recomplete()
  503.                     redraw()
  504.                 end
  505.  
  506.             elseif param == keys.home then
  507.                 -- Home
  508.                 if nPos > 0 then
  509.                     clear()
  510.                     nPos = 0
  511.                     recomplete()
  512.                     redraw()
  513.                 end
  514.  
  515.             elseif param == keys.delete then
  516.                 -- Delete
  517.                 if nPos < #sLine then
  518.                     clear()
  519.                     sLine = string.sub( sLine, 1, nPos ) .. string.sub( sLine, nPos + 2 )
  520.                     recomplete()
  521.                     redraw()
  522.                 end
  523.  
  524.             elseif param == keys["end"] then
  525.                 -- End
  526.                 if nPos < #sLine then
  527.                     clear()
  528.                     nPos = #sLine
  529.                     recomplete()
  530.                     redraw()
  531.                 end
  532.  
  533.             elseif param == keys.tab then
  534.                 -- Tab (accept autocomplete)
  535.                 acceptCompletion()
  536.  
  537.             end
  538.  
  539.         elseif sEvent == "mouse_click" or sEvent == "mouse_drag" and param == 1 then
  540.             local _, cy = term.getCursorPos()
  541.             if param1 >= sx and param1 <= w and param2 == cy then
  542.                 -- Ensure we don't scroll beyond the current line
  543.                 nPos = math.min(math.max(nScroll + param1 - sx, 0), #sLine)
  544.                 redraw()
  545.             end
  546.  
  547.         elseif sEvent == "term_resize" then
  548.             -- Terminal resized
  549.             w = term.getSize()
  550.             redraw()
  551.  
  552.         end
  553.     end
  554.  
  555.     local _, cy = term.getCursorPos()
  556.     term.setCursorBlink( false )
  557.     term.setCursorPos( w + 1, cy )
  558.     print()
  559.  
  560.     return sLine
  561. end
  562.  
  563. function loadfile( filename, mode, env )
  564.     -- Support the previous `loadfile(filename, env)` form instead.
  565.     if type(mode) == "table" and env == nil then
  566.         mode, env = nil, mode
  567.     end
  568.  
  569.     expect(1, filename, "string")
  570.     expect(2, mode, "string", "nil")
  571.     expect(3, env, "table", "nil")
  572.  
  573.     local file = fs.open( filename, "r" )
  574.     if not file then return nil, "File not found" end
  575.  
  576.     local func, err = load( file.readAll(), "@" .. fs.getName( filename ), mode, env )
  577.     file.close()
  578.     return func, err
  579. end
  580.  
  581. function dofile( _sFile )
  582.     expect(1, _sFile, "string")
  583.  
  584.     local fnFile, e = loadfile( _sFile, nil, _G )
  585.     if fnFile then
  586.         return fnFile()
  587.     else
  588.         error( e, 2 )
  589.     end
  590. end
  591.  
  592. -- Install the rest of the OS api
  593. function os.run( _tEnv, _sPath, ... )
  594.     expect(1, _tEnv, "table")
  595.     expect(2, _sPath, "string")
  596.  
  597.     local tArgs = table.pack( ... )
  598.     local tEnv = _tEnv
  599.     setmetatable( tEnv, { __index = _G } )
  600.     local fnFile, err = loadfile( _sPath, nil, tEnv )
  601.     if fnFile then
  602.         local ok, err = pcall( function()
  603.             fnFile( table.unpack( tArgs, 1, tArgs.n ) )
  604.         end )
  605.         if not ok then
  606.             if err and err ~= "" then
  607.                 printError( err )
  608.             end
  609.             return false
  610.         end
  611.         return true
  612.     end
  613.     if err and err ~= "" then
  614.         printError( err )
  615.     end
  616.     return false
  617. end
  618.  
  619. local tAPIsLoading = {}
  620. function os.loadAPI( _sPath )
  621.     expect(1, _sPath, "string")
  622.     local sName = fs.getName( _sPath )
  623.     if sName:sub(-4) == ".lua" then
  624.         sName = sName:sub(1, -5)
  625.     end
  626.     if tAPIsLoading[sName] == true then
  627.         printError( "API " .. sName .. " is already being loaded" )
  628.         return false
  629.     end
  630.     tAPIsLoading[sName] = true
  631.  
  632.     local tEnv = {}
  633.     setmetatable( tEnv, { __index = _G } )
  634.     local fnAPI, err = loadfile( _sPath, nil, tEnv )
  635.     if fnAPI then
  636.         local ok, err = pcall( fnAPI )
  637.         if not ok then
  638.             tAPIsLoading[sName] = nil
  639.             return error( "Failed to load API " .. sName .. " due to " .. err, 1 )
  640.         end
  641.     else
  642.         tAPIsLoading[sName] = nil
  643.         return error( "Failed to load API " .. sName .. " due to " .. err, 1 )
  644.     end
  645.  
  646.     local tAPI = {}
  647.     for k, v in pairs( tEnv ) do
  648.         if k ~= "_ENV" then
  649.             tAPI[k] =  v
  650.         end
  651.     end
  652.  
  653.     _G[sName] = tAPI
  654.     tAPIsLoading[sName] = nil
  655.     return true
  656. end
  657.  
  658. function os.unloadAPI( _sName )
  659.     expect(1, _sName, "string")
  660.     if _sName ~= "_G" and type(_G[_sName]) == "table" then
  661.         _G[_sName] = nil
  662.     end
  663. end
  664.  
  665. function os.sleep( nTime )
  666.     sleep( nTime )
  667. end
  668.  
  669. -- Install the lua part of the FS api
  670. local tEmpty = {}
  671. function fs.complete( sPath, sLocation, bIncludeFiles, bIncludeDirs )
  672.     expect(1, sPath, "string")
  673.     expect(2, sLocation, "string")
  674.     expect(3, bIncludeFiles, "boolean", "nil")
  675.     expect(4, bIncludeDirs, "boolean", "nil")
  676.  
  677.     bIncludeFiles = bIncludeFiles ~= false
  678.     bIncludeDirs = bIncludeDirs ~= false
  679.     local sDir = sLocation
  680.     local nStart = 1
  681.     local nSlash = string.find( sPath, "[/\\]", nStart )
  682.     if nSlash == 1 then
  683.         sDir = ""
  684.         nStart = 2
  685.     end
  686.     local sName
  687.     while not sName do
  688.         local nSlash = string.find( sPath, "[/\\]", nStart )
  689.         if nSlash then
  690.             local sPart = string.sub( sPath, nStart, nSlash - 1 )
  691.             sDir = fs.combine( sDir, sPart )
  692.             nStart = nSlash + 1
  693.         else
  694.             sName = string.sub( sPath, nStart )
  695.         end
  696.     end
  697.  
  698.     if fs.isDir( sDir ) then
  699.         local tResults = {}
  700.         if bIncludeDirs and sPath == "" then
  701.             table.insert( tResults, "." )
  702.         end
  703.         if sDir ~= "" then
  704.             if sPath == "" then
  705.                 table.insert( tResults, bIncludeDirs and ".." or "../" )
  706.             elseif sPath == "." then
  707.                 table.insert( tResults, bIncludeDirs and "." or "./" )
  708.             end
  709.         end
  710.         local tFiles = fs.list( sDir )
  711.         for n = 1, #tFiles do
  712.             local sFile = tFiles[n]
  713.             if #sFile >= #sName and string.sub( sFile, 1, #sName ) == sName then
  714.                 local bIsDir = fs.isDir( fs.combine( sDir, sFile ) )
  715.                 local sResult = string.sub( sFile, #sName + 1 )
  716.                 if bIsDir then
  717.                     table.insert( tResults, sResult .. "/" )
  718.                     if bIncludeDirs and #sResult > 0 then
  719.                         table.insert( tResults, sResult )
  720.                     end
  721.                 else
  722.                     if bIncludeFiles and #sResult > 0 then
  723.                         table.insert( tResults, sResult )
  724.                     end
  725.                 end
  726.             end
  727.         end
  728.         return tResults
  729.     end
  730.     return tEmpty
  731. end
  732.  
  733. -- Load APIs
  734. local bAPIError = false
  735. local tApis = fs.list( "rom/apis" )
  736. for _, sFile in ipairs( tApis ) do
  737.     if string.sub( sFile, 1, 1 ) ~= "." then
  738.         local sPath = fs.combine( "rom/apis", sFile )
  739.         if not fs.isDir( sPath ) then
  740.             if not os.loadAPI( sPath ) then
  741.                 bAPIError = true
  742.             end
  743.         end
  744.     end
  745. end
  746.  
  747. if turtle and fs.isDir( "rom/apis/turtle" ) then
  748.     -- Load turtle APIs
  749.     local tApis = fs.list( "rom/apis/turtle" )
  750.     for _, sFile in ipairs( tApis ) do
  751.         if string.sub( sFile, 1, 1 ) ~= "." then
  752.             local sPath = fs.combine( "rom/apis/turtle", sFile )
  753.             if not fs.isDir( sPath ) then
  754.                 if not os.loadAPI( sPath ) then
  755.                     bAPIError = true
  756.                 end
  757.             end
  758.         end
  759.     end
  760. end
  761.  
  762. if pocket and fs.isDir( "rom/apis/pocket" ) then
  763.     -- Load pocket APIs
  764.     local tApis = fs.list( "rom/apis/pocket" )
  765.     for _, sFile in ipairs( tApis ) do
  766.         if string.sub( sFile, 1, 1 ) ~= "." then
  767.             local sPath = fs.combine( "rom/apis/pocket", sFile )
  768.             if not fs.isDir( sPath ) then
  769.                 if not os.loadAPI( sPath ) then
  770.                     bAPIError = true
  771.                 end
  772.             end
  773.         end
  774.     end
  775. end
  776.  
  777. if commands and fs.isDir( "rom/apis/command" ) then
  778.     -- Load command APIs
  779.     if os.loadAPI( "rom/apis/command/commands.lua" ) then
  780.         -- Add a special case-insensitive metatable to the commands api
  781.         local tCaseInsensitiveMetatable = {
  782.             __index = function( table, key )
  783.                 local value = rawget( table, key )
  784.                 if value ~= nil then
  785.                     return value
  786.                 end
  787.                 if type(key) == "string" then
  788.                     local value = rawget( table, string.lower(key) )
  789.                     if value ~= nil then
  790.                         return value
  791.                     end
  792.                 end
  793.                 return nil
  794.             end,
  795.         }
  796.         setmetatable( commands, tCaseInsensitiveMetatable )
  797.         setmetatable( commands.async, tCaseInsensitiveMetatable )
  798.  
  799.         -- Add global "exec" function
  800.         exec = commands.exec
  801.     else
  802.         bAPIError = true
  803.     end
  804. end
  805.  
  806. if bAPIError then
  807.     print( "Press any key to continue" )
  808.     os.pullEvent( "key" )
  809.     term.clear()
  810.     term.setCursorPos( 1, 1 )
  811. end
  812.  
  813. -- Set default settings
  814. settings.set( "shell.allow_startup", true )
  815. settings.set( "shell.allow_disk_startup", commands == nil )
  816. settings.set( "shell.autocomplete", true )
  817. settings.set( "edit.autocomplete", true )
  818. settings.set( "edit.default_extension", "lua" )
  819. settings.set( "paint.default_extension", "nfp" )
  820. settings.set( "lua.autocomplete", true )
  821. settings.set( "list.show_hidden", false )
  822. settings.set( "motd.enable", false )
  823. settings.set( "motd.path", "/rom/motd.txt:/motd.txt" )
  824. if term.isColour() then
  825.     settings.set( "bios.use_multishell", true )
  826. end
  827. if _CC_DEFAULT_SETTINGS then
  828.     for sPair in string.gmatch( _CC_DEFAULT_SETTINGS, "[^,]+" ) do
  829.         local sName, sValue = string.match( sPair, "([^=]*)=(.*)" )
  830.         if sName and sValue then
  831.             local value
  832.             if sValue == "true" then
  833.                 value = true
  834.             elseif sValue == "false" then
  835.                 value = false
  836.             elseif sValue == "nil" then
  837.                 value = nil
  838.             elseif tonumber(sValue) then
  839.                 value = tonumber(sValue)
  840.             else
  841.                 value = sValue
  842.             end
  843.             if value ~= nil then
  844.                 settings.set( sName, value )
  845.             else
  846.                 settings.unset( sName )
  847.             end
  848.         end
  849.     end
  850. end
  851.  
  852. -- Load user settings
  853. if fs.exists( ".settings" ) then
  854.     settings.load( ".settings" )
  855. end
  856.  
  857. -- Run the shell
  858. local ok, err = pcall( function()
  859.     parallel.waitForAny(
  860.         function()
  861.             local sShell
  862.             if term.isColour() and settings.get( "bios.use_multishell" ) then
  863.                 sShell = "rom/programs/advanced/multishell.lua"
  864.             else
  865.                 sShell = "rom/programs/shell.lua"
  866.             end
  867.             os.run( {}, sShell )
  868.             os.run( {}, "rom/programs/shutdown.lua" )
  869.         end,
  870.         function()
  871.             rednet.run()
  872.         end )
  873. end )
  874.  
  875. -- If the shell errored, let the user read it.
  876. term.redirect( term.native() )
  877. if not ok then
  878.     printError( err )
  879.     pcall( function()
  880.         term.setCursorBlink( false )
  881.         print( "Press any key to continue" )
  882.         os.pullEvent( "key" )
  883.     end )
  884. end
  885.  
  886. -- End
  887. os.shutdown()
Add Comment
Please, Sign In to add comment