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