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