· 2 years ago · Jun 12, 2023, 07:50 PM
1--simply run and this installer will install the bios
2-- computer must be manunly rebooted : for human error reasons explaied later i will not autoreboot the computer
3--WARNING: do not install unless you have a CustomOS that uses this Bios or have access to the real files system installing
4-- this without a CustomOS that uses this will be destory as CraftOS not be loaded if a no boot loader found error is called
5local Argue = {...}
6 local expect = require("cc.expect").expect
7 local Path
8 if false
9 then
10 Path = expect(1,Argue[1],"string","nil") or ""
11 if not fs.exists(Path)
12 then
13 error(("%s not found"):format(Path),2)
14 end
15 if not fs.isDir(Path)
16 then
17 error(("%s is not directory"):format(Path),2)
18 end
19 end
20 local programs = "{\
21 {\
22 func = \"\\\
23\\\
24\\\
25 000000000\\\
26 000 00\\\
27 00 0\\\
28 0 0\\\
29 0\\\
30 00 00000\\\
31 00 0\\\
32 00 00\\\
33 00000000\\\
34\",\
35 Path = \"boot/Image.nfp\",\
36 },\
37 {\
38 func = \"--[[- The Colors API allows you to manipulate sets of colors.\\\
39\\\
40This is useful in conjunction with Bundled Cables from the RedPower mod, RedNet\\\
41Cables from the MineFactory Reloaded mod, and colors on Advanced Computers and\\\
42Advanced Monitors.\\\
43\\\
44For the non-American English version just replace @{colors} with @{colours} and\\\
45it will use the other API, colours which is exactly the same, except in British\\\
46English (e.g. @{colors.gray} is spelt @{colours.grey}).\\\
47\\\
48On basic terminals (such as the Computer and Monitor), all the colors are\\\
49converted to grayscale. This means you can still use all 16 colors on the\\\
50screen, but they will appear as the nearest tint of gray. You can check if a\\\
51terminal supports color by using the function @{term.isColor}.\\\
52\\\
53Grayscale colors are calculated by taking the average of the three components,\\\
54i.e. `(red + green + blue) / 3`.\\\
55\\\
56<table class=\\\"pretty-table\\\">\\\
57<thead>\\\
58 <tr><th colspan=\\\"8\\\" align=\\\"center\\\">Default Colors</th></tr>\\\
59 <tr>\\\
60 <th rowspan=\\\"2\\\" align=\\\"center\\\">Color</th>\\\
61 <th colspan=\\\"3\\\" align=\\\"center\\\">Value</th>\\\
62 <th colspan=\\\"4\\\" align=\\\"center\\\">Default Palette Color</th>\\\
63 </tr>\\\
64 <tr>\\\
65 <th>Dec</th><th>Hex</th><th>Paint/Blit</th>\\\
66 <th>Preview</th><th>Hex</th><th>RGB</th><th>Grayscale</th>\\\
67 </tr>\\\
68</thead>\\\
69<tbody>\\\
70 <tr>\\\
71 <td><code>colors.white</code></td>\\\
72 <td align=\\\"right\\\">1</td><td align=\\\"right\\\">0x1</td><td align=\\\"right\\\">0</td>\\\
73 <td style=\\\"background:#F0F0F0\\\"></td><td>#F0F0F0</td><td>240, 240, 240</td>\\\
74 <td style=\\\"background:#F0F0F0\\\"></td>\\\
75 </tr>\\\
76 <tr>\\\
77 <td><code>colors.orange</code></td>\\\
78 <td align=\\\"right\\\">2</td><td align=\\\"right\\\">0x2</td><td align=\\\"right\\\">1</td>\\\
79 <td style=\\\"background:#F2B233\\\"></td><td>#F2B233</td><td>242, 178, 51</td>\\\
80 <td style=\\\"background:#9D9D9D\\\"></td>\\\
81 </tr>\\\
82 <tr>\\\
83 <td><code>colors.magenta</code></td>\\\
84 <td align=\\\"right\\\">4</td><td align=\\\"right\\\">0x4</td><td align=\\\"right\\\">2</td>\\\
85 <td style=\\\"background:#E57FD8\\\"></td><td>#E57FD8</td><td>229, 127, 216</td>\\\
86 <td style=\\\"background:#BEBEBE\\\"></td>\\\
87 </tr>\\\
88 <tr>\\\
89 <td><code>colors.lightBlue</code></td>\\\
90 <td align=\\\"right\\\">8</td><td align=\\\"right\\\">0x8</td><td align=\\\"right\\\">3</td>\\\
91 <td style=\\\"background:#99B2F2\\\"></td><td>#99B2F2</td><td>153, 178, 242</td>\\\
92 <td style=\\\"background:#BFBFBF\\\"></td>\\\
93 </tr>\\\
94 <tr>\\\
95 <td><code>colors.yellow</code></td>\\\
96 <td align=\\\"right\\\">16</td><td align=\\\"right\\\">0x10</td><td align=\\\"right\\\">4</td>\\\
97 <td style=\\\"background:#DEDE6C\\\"></td><td>#DEDE6C</td><td>222, 222, 108</td>\\\
98 <td style=\\\"background:#B8B8B8\\\"></td>\\\
99 </tr>\\\
100 <tr>\\\
101 <td><code>colors.lime</code></td>\\\
102 <td align=\\\"right\\\">32</td><td align=\\\"right\\\">0x20</td><td align=\\\"right\\\">5</td>\\\
103 <td style=\\\"background:#7FCC19\\\"></td><td>#7FCC19</td><td>127, 204, 25</td>\\\
104 <td style=\\\"background:#767676\\\"></td>\\\
105 </tr>\\\
106 <tr>\\\
107 <td><code>colors.pink</code></td>\\\
108 <td align=\\\"right\\\">64</td><td align=\\\"right\\\">0x40</td><td align=\\\"right\\\">6</td>\\\
109 <td style=\\\"background:#F2B2CC\\\"></td><td>#F2B2CC</td><td>242, 178, 204</td>\\\
110 <td style=\\\"background:#D0D0D0\\\"></td>\\\
111 </tr>\\\
112 <tr>\\\
113 <td><code>colors.gray</code></td>\\\
114 <td align=\\\"right\\\">128</td><td align=\\\"right\\\">0x80</td><td align=\\\"right\\\">7</td>\\\
115 <td style=\\\"background:#4C4C4C\\\"></td><td>#4C4C4C</td><td>76, 76, 76</td>\\\
116 <td style=\\\"background:#4C4C4C\\\"></td>\\\
117 </tr>\\\
118 <tr>\\\
119 <td><code>colors.lightGray</code></td>\\\
120 <td align=\\\"right\\\">256</td><td align=\\\"right\\\">0x100</td><td align=\\\"right\\\">8</td>\\\
121 <td style=\\\"background:#999999\\\"></td><td>#999999</td><td>153, 153, 153</td>\\\
122 <td style=\\\"background:#999999\\\"></td>\\\
123 </tr>\\\
124 <tr>\\\
125 <td><code>colors.cyan</code></td>\\\
126 <td align=\\\"right\\\">512</td><td align=\\\"right\\\">0x200</td><td align=\\\"right\\\">9</td>\\\
127 <td style=\\\"background:#4C99B2\\\"></td><td>#4C99B2</td><td>76, 153, 178</td>\\\
128 <td style=\\\"background:#878787\\\"></td>\\\
129 </tr>\\\
130 <tr>\\\
131 <td><code>colors.purple</code></td>\\\
132 <td align=\\\"right\\\">1024</td><td align=\\\"right\\\">0x400</td><td align=\\\"right\\\">a</td>\\\
133 <td style=\\\"background:#B266E5\\\"></td><td>#B266E5</td><td>178, 102, 229</td>\\\
134 <td style=\\\"background:#A9A9A9\\\"></td>\\\
135 </tr>\\\
136 <tr>\\\
137 <td><code>colors.blue</code></td>\\\
138 <td align=\\\"right\\\">2048</td><td align=\\\"right\\\">0x800</td><td align=\\\"right\\\">b</td>\\\
139 <td style=\\\"background:#3366CC\\\"></td><td>#3366CC</td><td>51, 102, 204</td>\\\
140 <td style=\\\"background:#777777\\\"></td>\\\
141 </tr>\\\
142 <tr>\\\
143 <td><code>colors.brown</code></td>\\\
144 <td align=\\\"right\\\">4096</td><td align=\\\"right\\\">0x1000</td><td align=\\\"right\\\">c</td>\\\
145 <td style=\\\"background:#7F664C\\\"></td><td>#7F664C</td><td>127, 102, 76</td>\\\
146 <td style=\\\"background:#656565\\\"></td>\\\
147 </tr>\\\
148 <tr>\\\
149 <td><code>colors.green</code></td>\\\
150 <td align=\\\"right\\\">8192</td><td align=\\\"right\\\">0x2000</td><td align=\\\"right\\\">d</td>\\\
151 <td style=\\\"background:#57A64E\\\"></td><td>#57A64E</td><td>87, 166, 78</td>\\\
152 <td style=\\\"background:#6E6E6E\\\"></td>\\\
153 </tr>\\\
154 <tr>\\\
155 <td><code>colors.red</code></td>\\\
156 <td align=\\\"right\\\">16384</td><td align=\\\"right\\\">0x4000</td><td align=\\\"right\\\">e</td>\\\
157 <td style=\\\"background:#CC4C4C\\\"></td><td>#CC4C4C</td><td>204, 76, 76</td>\\\
158 <td style=\\\"background:#767676\\\"></td>\\\
159 </tr>\\\
160 <tr>\\\
161 <td><code>colors.black</code></td>\\\
162 <td align=\\\"right\\\">32768</td><td align=\\\"right\\\">0x8000</td><td align=\\\"right\\\">f</td>\\\
163 <td style=\\\"background:#111111\\\"></td><td>#111111</td><td>17, 17, 17</td>\\\
164 <td style=\\\"background:#111111\\\"></td>\\\
165 </tr>\\\
166</tbody>\\\
167</table>\\\
168\\\
169@see colours\\\
170@module colors\\\
171]]\\\
172\\\
173local expect = os.dofile(\\\"rom/modules/main/cc/expect.lua\\\",_ENV).expect\\\
174--- White: Written as `0` in paint files and @{term.blit}, has a default\\\
175-- terminal colour of #F0F0F0.\\\
176white = 0x1\\\
177\\\
178--- Orange: Written as `1` in paint files and @{term.blit}, has a\\\
179-- default terminal colour of #F2B233.\\\
180orange = 0x2\\\
181\\\
182--- Magenta: Written as `2` in paint files and @{term.blit}, has a\\\
183-- default terminal colour of #E57FD8.\\\
184magenta = 0x4\\\
185\\\
186--- Light blue: Written as `3` in paint files and @{term.blit}, has a\\\
187-- default terminal colour of #99B2F2.\\\
188lightBlue = 0x8\\\
189\\\
190--- Yellow: Written as `4` in paint files and @{term.blit}, has a\\\
191-- default terminal colour of #DEDE6C.\\\
192yellow = 0x10\\\
193\\\
194--- Lime: Written as `5` in paint files and @{term.blit}, has a default\\\
195-- terminal colour of #7FCC19.\\\
196lime = 0x20\\\
197\\\
198--- Pink: Written as `6` in paint files and @{term.blit}, has a default\\\
199-- terminal colour of #F2B2CC.\\\
200pink = 0x40\\\
201\\\
202--- Gray: Written as `7` in paint files and @{term.blit}, has a default\\\
203-- terminal colour of #4C4C4C.\\\
204gray = 0x80\\\
205\\\
206--- Light gray: Written as `8` in paint files and @{term.blit}, has a\\\
207-- default terminal colour of #999999.\\\
208lightGray = 0x100\\\
209\\\
210--- Cyan: Written as `9` in paint files and @{term.blit}, has a default\\\
211-- terminal colour of #4C99B2.\\\
212cyan = 0x200\\\
213\\\
214--- Purple: Written as `a` in paint files and @{term.blit}, has a\\\
215-- default terminal colour of #B266E5.\\\
216purple = 0x400\\\
217\\\
218--- Blue: Written as `b` in paint files and @{term.blit}, has a default\\\
219-- terminal colour of #3366CC.\\\
220blue = 0x800\\\
221\\\
222--- Brown: Written as `c` in paint files and @{term.blit}, has a default\\\
223-- terminal colour of #7F664C.\\\
224brown = 0x1000\\\
225\\\
226--- Green: Written as `d` in paint files and @{term.blit}, has a default\\\
227-- terminal colour of #57A64E.\\\
228green = 0x2000\\\
229\\\
230--- Red: Written as `e` in paint files and @{term.blit}, has a default\\\
231-- terminal colour of #CC4C4C.\\\
232red = 0x4000\\\
233\\\
234--- Black: Written as `f` in paint files and @{term.blit}, has a default\\\
235-- terminal colour of #111111.\\\
236black = 0x8000\\\
237\\\
238--- Combines a set of colors (or sets of colors) into a larger set. Useful for\\\
239-- Bundled Cables.\\\
240--\\\
241-- @tparam number ... The colors to combine.\\\
242-- @treturn number The union of the color sets given in `...`\\\
243-- @since 1.2\\\
244-- @usage\\\
245-- ```lua\\\
246-- colors.combine(colors.white, colors.magenta, colours.lightBlue)\\\
247-- -- => 13\\\
248-- ```\\\
249function combine(...)\\\
250 local r = 0\\\
251 for i = 1, select('#', ...) do\\\
252 local c = select(i, ...)\\\
253 expect(i, c, \\\"number\\\")\\\
254 r = bit32.bor(r, c)\\\
255 end\\\
256 return r\\\
257end\\\
258\\\
259--- Removes one or more colors (or sets of colors) from an initial set. Useful\\\
260-- for Bundled Cables.\\\
261--\\\
262-- Each parameter beyond the first may be a single color or may be a set of\\\
263-- colors (in the latter case, all colors in the set are removed from the\\\
264-- original set).\\\
265--\\\
266-- @tparam number colors The color from which to subtract.\\\
267-- @tparam number ... The colors to subtract.\\\
268-- @treturn number The resulting color.\\\
269-- @since 1.2\\\
270-- @usage\\\
271-- ```lua\\\
272-- colours.subtract(colours.lime, colours.orange, colours.white)\\\
273-- -- => 32\\\
274-- ```\\\
275function subtract(colors, ...)\\\
276 expect(1, colors, \\\"number\\\")\\\
277 local r = colors\\\
278 for i = 1, select('#', ...) do\\\
279 local c = select(i, ...)\\\
280 expect(i + 1, c, \\\"number\\\")\\\
281 r = bit32.band(r, bit32.bnot(c))\\\
282 end\\\
283 return r\\\
284end\\\
285\\\
286--- Tests whether `color` is contained within `colors`. Useful for Bundled\\\
287-- Cables.\\\
288--\\\
289-- @tparam number colors A color, or color set\\\
290-- @tparam number color A color or set of colors that `colors` should contain.\\\
291-- @treturn boolean If `colors` contains all colors within `color`.\\\
292-- @since 1.2\\\
293-- @usage\\\
294-- ```lua\\\
295-- colors.test(colors.combine(colors.white, colors.magenta, colours.lightBlue), colors.lightBlue)\\\
296-- -- => true\\\
297-- ```\\\
298function test(colors, color)\\\
299 expect(1, colors, \\\"number\\\")\\\
300 expect(2, color, \\\"number\\\")\\\
301 return bit32.band(colors, color) == color\\\
302end\\\
303\\\
304--- Combine a three-colour RGB value into one hexadecimal representation.\\\
305--\\\
306-- @tparam number r The red channel, should be between 0 and 1.\\\
307-- @tparam number g The red channel, should be between 0 and 1.\\\
308-- @tparam number b The blue channel, should be between 0 and 1.\\\
309-- @treturn number The combined hexadecimal colour.\\\
310-- @usage\\\
311-- ```lua\\\
312-- colors.packRGB(0.7, 0.2, 0.6)\\\
313-- -- => 0xb23399\\\
314-- ```\\\
315-- @since 1.81.0\\\
316function packRGB(r, g, b)\\\
317 expect(1, r, \\\"number\\\")\\\
318 expect(2, g, \\\"number\\\")\\\
319 expect(3, b, \\\"number\\\")\\\
320 return\\\
321 bit32.band(r * 255, 0xFF) * 2 ^ 16 +\\\
322 bit32.band(g * 255, 0xFF) * 2 ^ 8 +\\\
323 bit32.band(b * 255, 0xFF)\\\
324end\\\
325\\\
326--- Separate a hexadecimal RGB colour into its three constituent channels.\\\
327--\\\
328-- @tparam number rgb The combined hexadecimal colour.\\\
329-- @treturn number The red channel, will be between 0 and 1.\\\
330-- @treturn number The red channel, will be between 0 and 1.\\\
331-- @treturn number The blue channel, will be between 0 and 1.\\\
332-- @usage\\\
333-- ```lua\\\
334-- colors.unpackRGB(0xb23399)\\\
335-- -- => 0.7, 0.2, 0.6\\\
336-- ```\\\
337-- @see colors.packRGB\\\
338-- @since 1.81.0\\\
339function unpackRGB(rgb)\\\
340 expect(1, rgb, \\\"number\\\")\\\
341 return\\\
342 bit32.band(bit32.rshift(rgb, 16), 0xFF) / 255,\\\
343 bit32.band(bit32.rshift(rgb, 8), 0xFF) / 255,\\\
344 bit32.band(rgb, 0xFF) / 255\\\
345end\\\
346\\\
347--- Either calls @{colors.packRGB} or @{colors.unpackRGB}, depending on how many\\\
348-- arguments it receives.\\\
349--\\\
350-- @tparam[1] number r The red channel, as an argument to @{colors.packRGB}.\\\
351-- @tparam[1] number g The green channel, as an argument to @{colors.packRGB}.\\\
352-- @tparam[1] number b The blue channel, as an argument to @{colors.packRGB}.\\\
353-- @tparam[2] number rgb The combined hexadecimal color, as an argument to @{colors.unpackRGB}.\\\
354-- @treturn[1] number The combined hexadecimal colour, as returned by @{colors.packRGB}.\\\
355-- @treturn[2] number The red channel, as returned by @{colors.unpackRGB}\\\
356-- @treturn[2] number The green channel, as returned by @{colors.unpackRGB}\\\
357-- @treturn[2] number The blue channel, as returned by @{colors.unpackRGB}\\\
358-- @deprecated Use @{packRGB} or @{unpackRGB} directly.\\\
359-- @usage\\\
360-- ```lua\\\
361-- colors.rgb8(0xb23399)\\\
362-- -- => 0.7, 0.2, 0.6\\\
363-- ```\\\
364-- @usage\\\
365-- ```lua\\\
366-- colors.rgb8(0.7, 0.2, 0.6)\\\
367-- -- => 0xb23399\\\
368-- ```\\\
369-- @since 1.80pr1\\\
370-- @changed 1.81.0 Deprecated in favor of colors.(un)packRGB.\\\
371function rgb8(r, g, b)\\\
372 if g == nil and b == nil then\\\
373 return unpackRGB(r)\\\
374 else\\\
375 return packRGB(r, g, b)\\\
376 end\\\
377end\\\
378\\\
379-- Colour to hex lookup table for toBlit\\\
380local color_hex_lookup = {}\\\
381for i = 0, 15 do\\\
382 color_hex_lookup[2 ^ i] = string.format(\\\"%x\\\", i)\\\
383end\\\
384\\\
385--- Converts the given color to a paint/blit hex character (0-9a-f).\\\
386--\\\
387-- This is equivalent to converting floor(log_2(color)) to hexadecimal.\\\
388--\\\
389-- @tparam number color The color to convert.\\\
390-- @treturn string The blit hex code of the color.\\\
391-- @since 1.94.0\\\
392function toBlit(color)\\\
393 expect(1, color, \\\"number\\\")\\\
394 return color_hex_lookup[color] or\\\
395 string.format(\\\"%x\\\", math.floor(math.log(color) / math.log(2)))\\\
396end\\\
397\",\
398 Path = \"boot/apis/colors.lua\",\
399 },\
400 {\
401 func = \"--- Emulates Lua's standard [io library][io].\\\
402--\\\
403-- [io]: https://www.lua.org/manual/5.1/manual.html#5.7\\\
404--\\\
405-- @module io\\\
406\\\
407local expect, type_of = os.dofile(\\\"rom/modules/main/cc/expect.lua\\\",_ENV).expect, _G.type\\\
408\\\
409--- If we return nil then close the file, as we've reached the end.\\\
410-- We use this weird wrapper function as we wish to preserve the varargs\\\
411local function checkResult(handle, ...)\\\
412 if ... == nil and handle._autoclose and not handle._closed then handle:close() end\\\
413 return ...\\\
414end\\\
415\\\
416--- A file handle which can be read or written to.\\\
417--\\\
418-- @type Handle\\\
419local handleMetatable\\\
420handleMetatable = {\\\
421 __name = \\\"FILE*\\\",\\\
422 __tostring = function(self)\\\
423 if self._closed then\\\
424 return \\\"file (closed)\\\"\\\
425 else\\\
426 local hash = tostring(self._handle):match(\\\"table: (%x+)\\\")\\\
427 return \\\"file (\\\" .. hash .. \\\")\\\"\\\
428 end\\\
429 end,\\\
430\\\
431 __index = {\\\
432 --- Close this file handle, freeing any resources it uses.\\\
433 --\\\
434 -- @treturn[1] true If this handle was successfully closed.\\\
435 -- @treturn[2] nil If this file handle could not be closed.\\\
436 -- @treturn[2] string The reason it could not be closed.\\\
437 -- @throws If this handle was already closed.\\\
438 close = function(self)\\\
439 if type_of(self) ~= \\\"table\\\" or getmetatable(self) ~= handleMetatable then\\\
440 error(\\\"bad argument #1 (FILE expected, got \\\" .. type_of(self) .. \\\")\\\", 2)\\\
441 end\\\
442 if self._closed then error(\\\"attempt to use a closed file\\\", 2) end\\\
443\\\
444 local handle = self._handle\\\
445 if handle.close then\\\
446 self._closed = true\\\
447 handle.close()\\\
448 return true\\\
449 else\\\
450 return nil, \\\"attempt to close standard stream\\\"\\\
451 end\\\
452 end,\\\
453\\\
454 --- Flush any buffered output, forcing it to be written to the file\\\
455 --\\\
456 -- @throws If the handle has been closed\\\
457 flush = function(self)\\\
458 if type_of(self) ~= \\\"table\\\" or getmetatable(self) ~= handleMetatable then\\\
459 error(\\\"bad argument #1 (FILE expected, got \\\" .. type_of(self) .. \\\")\\\", 2)\\\
460 end\\\
461 if self._closed then error(\\\"attempt to use a closed file\\\", 2) end\\\
462\\\
463 local handle = self._handle\\\
464 if handle.flush then handle.flush() end\\\
465 return true\\\
466 end,\\\
467\\\
468 --[[- Returns an iterator that, each time it is called, returns a new\\\
469 line from the file.\\\
470\\\
471 This can be used in a for loop to iterate over all lines of a file\\\
472\\\
473 Once the end of the file has been reached, @{nil} will be returned. The file is\\\
474 *not* automatically closed.\\\
475\\\
476 @param ... The argument to pass to @{Handle:read} for each line.\\\
477 @treturn function():string|nil The line iterator.\\\
478 @throws If the file cannot be opened for reading\\\
479 @since 1.3\\\
480\\\
481 @see io.lines\\\
482 @usage Iterate over every line in a file and print it out.\\\
483\\\
484 ```lua\\\
485 local file = io.open(\\\"/rom/help/intro.txt\\\")\\\
486 for line in file:lines() do\\\
487 print(line)\\\
488 end\\\
489 file:close()\\\
490 ```\\\
491 ]]\\\
492 lines = function(self, ...)\\\
493 if type_of(self) ~= \\\"table\\\" or getmetatable(self) ~= handleMetatable then\\\
494 error(\\\"bad argument #1 (FILE expected, got \\\" .. type_of(self) .. \\\")\\\", 2)\\\
495 end\\\
496 if self._closed then error(\\\"attempt to use a closed file\\\", 2) end\\\
497\\\
498 local handle = self._handle\\\
499 if not handle.read then return nil, \\\"file is not readable\\\" end\\\
500\\\
501 local args = table.pack(...)\\\
502 return function()\\\
503 if self._closed then error(\\\"file is already closed\\\", 2) end\\\
504 return checkResult(self, self:read(table.unpack(args, 1, args.n)))\\\
505 end\\\
506 end,\\\
507\\\
508 --[[- Reads data from the file, using the specified formats. For each\\\
509 format provided, the function returns either the data read, or `nil` if\\\
510 no data could be read.\\\
511\\\
512 The following formats are available:\\\
513 - `l`: Returns the next line (without a newline on the end).\\\
514 - `L`: Returns the next line (with a newline on the end).\\\
515 - `a`: Returns the entire rest of the file.\\\
516 - ~~`n`: Returns a number~~ (not implemented in CC).\\\
517\\\
518 These formats can be preceded by a `*` to make it compatible with Lua 5.1.\\\
519\\\
520 If no format is provided, `l` is assumed.\\\
521\\\
522 @param ... The formats to use.\\\
523 @treturn (string|nil)... The data read from the file.\\\
524 ]]\\\
525 read = function(self, ...)\\\
526 if type_of(self) ~= \\\"table\\\" or getmetatable(self) ~= handleMetatable then\\\
527 error(\\\"bad argument #1 (FILE expected, got \\\" .. type_of(self) .. \\\")\\\", 2)\\\
528 end\\\
529 if self._closed then error(\\\"attempt to use a closed file\\\", 2) end\\\
530\\\
531 local handle = self._handle\\\
532 if not handle.read and not handle.readLine then return nil, \\\"Not opened for reading\\\" end\\\
533\\\
534 local n = select(\\\"#\\\", ...)\\\
535 local output = {}\\\
536 for i = 1, n do\\\
537 local arg = select(i, ...)\\\
538 local res\\\
539 if type_of(arg) == \\\"number\\\" then\\\
540 if handle.read then res = handle.read(arg) end\\\
541 elseif type_of(arg) == \\\"string\\\" then\\\
542 local format = arg:gsub(\\\"^%*\\\", \\\"\\\"):sub(1, 1)\\\
543\\\
544 if format == \\\"l\\\" then\\\
545 if handle.readLine then res = handle.readLine() end\\\
546 elseif format == \\\"L\\\" and handle.readLine then\\\
547 if handle.readLine then res = handle.readLine(true) end\\\
548 elseif format == \\\"a\\\" then\\\
549 if handle.readAll then res = handle.readAll() or \\\"\\\" end\\\
550 elseif format == \\\"n\\\" then\\\
551 res = nil -- Skip this format as we can't really handle it\\\
552 else\\\
553 error(\\\"bad argument #\\\" .. i .. \\\" (invalid format)\\\", 2)\\\
554 end\\\
555 else\\\
556 error(\\\"bad argument #\\\" .. i .. \\\" (expected string, got \\\" .. type_of(arg) .. \\\")\\\", 2)\\\
557 end\\\
558\\\
559 output[i] = res\\\
560 if not res then break end\\\
561 end\\\
562\\\
563 -- Default to \\\"l\\\" if possible\\\
564 if n == 0 and handle.readLine then return handle.readLine() end\\\
565 return table.unpack(output, 1, n)\\\
566 end,\\\
567\\\
568 --[[- Seeks the file cursor to the specified position, and returns the\\\
569 new position.\\\
570\\\
571 `whence` controls where the seek operation starts, and is a string that\\\
572 may be one of these three values:\\\
573 - `set`: base position is 0 (beginning of the file)\\\
574 - `cur`: base is current position\\\
575 - `end`: base is end of file\\\
576\\\
577 The default value of `whence` is `cur`, and the default value of `offset`\\\
578 is 0. This means that `file:seek()` without arguments returns the current\\\
579 position without moving.\\\
580\\\
581 @tparam[opt] string whence The place to set the cursor from.\\\
582 @tparam[opt] number offset The offset from the start to move to.\\\
583 @treturn number The new location of the file cursor.\\\
584 ]]\\\
585 seek = function(self, whence, offset)\\\
586 if type_of(self) ~= \\\"table\\\" or getmetatable(self) ~= handleMetatable then\\\
587 error(\\\"bad argument #1 (FILE expected, got \\\" .. type_of(self) .. \\\")\\\", 2)\\\
588 end\\\
589 if self._closed then error(\\\"attempt to use a closed file\\\", 2) end\\\
590\\\
591 local handle = self._handle\\\
592 if not handle.seek then return nil, \\\"file is not seekable\\\" end\\\
593\\\
594 -- It's a tail call, so error positions are preserved\\\
595 return handle.seek(whence, offset)\\\
596 end,\\\
597\\\
598 --[[- Sets the buffering mode for an output file.\\\
599\\\
600 This has no effect under ComputerCraft, and exists with compatility\\\
601 with base Lua.\\\
602 @tparam string mode The buffering mode.\\\
603 @tparam[opt] number size The size of the buffer.\\\
604 @see file:setvbuf Lua's documentation for `setvbuf`.\\\
605 @deprecated This has no effect in CC.\\\
606 ]]\\\
607 setvbuf = function(self, mode, size) end,\\\
608\\\
609 --- Write one or more values to the file\\\
610 --\\\
611 -- @tparam string|number ... The values to write.\\\
612 -- @treturn[1] Handle The current file, allowing chained calls.\\\
613 -- @treturn[2] nil If the file could not be written to.\\\
614 -- @treturn[2] string The error message which occurred while writing.\\\
615 -- @changed 1.81.0 Multiple arguments are now allowed.\\\
616 write = function(self, ...)\\\
617 if type_of(self) ~= \\\"table\\\" or getmetatable(self) ~= handleMetatable then\\\
618 error(\\\"bad argument #1 (FILE expected, got \\\" .. type_of(self) .. \\\")\\\", 2)\\\
619 end\\\
620 if self._closed then error(\\\"attempt to use a closed file\\\", 2) end\\\
621\\\
622 local handle = self._handle\\\
623 if not handle.write then return nil, \\\"file is not writable\\\" end\\\
624\\\
625 for i = 1, select(\\\"#\\\", ...) do\\\
626 local arg = select(i, ...)\\\
627 expect(i, arg, \\\"string\\\", \\\"number\\\")\\\
628 handle.write(arg)\\\
629 end\\\
630 return self\\\
631 end,\\\
632 },\\\
633}\\\
634\\\
635local function make_file(handle)\\\
636 return setmetatable({ _handle = handle }, handleMetatable)\\\
637end\\\
638\\\
639local defaultInput = make_file({ readLine = _G.read })\\\
640\\\
641local defaultOutput = make_file({ write = _G.write })\\\
642\\\
643local defaultError = make_file({\\\
644 write = function(...)\\\
645 local oldColour\\\
646 if term.isColour() then\\\
647 oldColour = term.getTextColour()\\\
648 term.setTextColour(colors.red)\\\
649 end\\\
650 _G.write(...)\\\
651 if term.isColour() then term.setTextColour(oldColour) end\\\
652 end,\\\
653})\\\
654\\\
655local currentInput = defaultInput\\\
656local currentOutput = defaultOutput\\\
657\\\
658--- A file handle representing the \\\"standard input\\\". Reading from this\\\
659-- file will prompt the user for input.\\\
660stdin = defaultInput\\\
661\\\
662--- A file handle representing the \\\"standard output\\\". Writing to this\\\
663-- file will display the written text to the screen.\\\
664stdout = defaultOutput\\\
665\\\
666--- A file handle representing the \\\"standard error\\\" stream.\\\
667--\\\
668-- One may use this to display error messages, writing to it will display\\\
669-- them on the terminal.\\\
670stderr = defaultError\\\
671\\\
672--- Closes the provided file handle.\\\
673--\\\
674-- @tparam[opt] Handle file The file handle to close, defaults to the\\\
675-- current output file.\\\
676--\\\
677-- @see Handle:close\\\
678-- @see io.output\\\
679-- @since 1.55\\\
680function close(file)\\\
681 if file == nil then return currentOutput:close() end\\\
682\\\
683 if type_of(file) ~= \\\"table\\\" or getmetatable(file) ~= handleMetatable then\\\
684 error(\\\"bad argument #1 (FILE expected, got \\\" .. type_of(file) .. \\\")\\\", 2)\\\
685 end\\\
686 return file:close()\\\
687end\\\
688\\\
689--- Flushes the current output file.\\\
690--\\\
691-- @see Handle:flush\\\
692-- @see io.output\\\
693-- @since 1.55\\\
694function flush()\\\
695 return currentOutput:flush()\\\
696end\\\
697\\\
698--- Get or set the current input file.\\\
699--\\\
700-- @tparam[opt] Handle|string file The new input file, either as a file path or pre-existing handle.\\\
701-- @treturn Handle The current input file.\\\
702-- @throws If the provided filename cannot be opened for reading.\\\
703-- @since 1.55\\\
704function input(file)\\\
705 if type_of(file) == \\\"string\\\" then\\\
706 local res, err = open(file, \\\"rb\\\")\\\
707 if not res then error(err, 2) end\\\
708 currentInput = res\\\
709 elseif type_of(file) == \\\"table\\\" and getmetatable(file) == handleMetatable then\\\
710 currentInput = file\\\
711 elseif file ~= nil then\\\
712 error(\\\"bad fileument #1 (FILE expected, got \\\" .. type_of(file) .. \\\")\\\", 2)\\\
713 end\\\
714\\\
715 return currentInput\\\
716end\\\
717\\\
718--[[- Opens the given file name in read mode and returns an iterator that,\\\
719each time it is called, returns a new line from the file.\\\
720\\\
721This can be used in a for loop to iterate over all lines of a file\\\
722\\\
723Once the end of the file has been reached, @{nil} will be returned. The file is\\\
724automatically closed.\\\
725\\\
726If no file name is given, the @{io.input|current input} will be used instead.\\\
727In this case, the handle is not used.\\\
728\\\
729@tparam[opt] string filename The name of the file to extract lines from\\\
730@param ... The argument to pass to @{Handle:read} for each line.\\\
731@treturn function():string|nil The line iterator.\\\
732@throws If the file cannot be opened for reading\\\
733\\\
734@see Handle:lines\\\
735@see io.input\\\
736@since 1.55\\\
737@usage Iterate over every line in a file and print it out.\\\
738\\\
739```lua\\\
740for line in io.lines(\\\"/rom/help/intro.txt\\\") do\\\
741 print(line)\\\
742end\\\
743```\\\
744]]\\\
745function lines(filename, ...)\\\
746 expect(1, filename, \\\"string\\\", \\\"nil\\\")\\\
747 if filename then\\\
748 local ok, err = open(filename, \\\"rb\\\")\\\
749 if not ok then error(err, 2) end\\\
750\\\
751 -- We set this magic flag to mark this file as being opened by io.lines and so should be\\\
752 -- closed automatically\\\
753 ok._autoclose = true\\\
754 return ok:lines(...)\\\
755 else\\\
756 return currentInput:lines(...)\\\
757 end\\\
758end\\\
759\\\
760--- Open a file with the given mode, either returning a new file handle\\\
761-- or @{nil}, plus an error message.\\\
762--\\\
763-- The `mode` string can be any of the following:\\\
764-- - **\\\"r\\\"**: Read mode\\\
765-- - **\\\"w\\\"**: Write mode\\\
766-- - **\\\"a\\\"**: Append mode\\\
767--\\\
768-- The mode may also have a `b` at the end, which opens the file in \\\"binary\\\
769-- mode\\\". This allows you to read binary files, as well as seek within a file.\\\
770--\\\
771-- @tparam string filename The name of the file to open.\\\
772-- @tparam[opt] string mode The mode to open the file with. This defaults to `rb`.\\\
773-- @treturn[1] Handle The opened file.\\\
774-- @treturn[2] nil In case of an error.\\\
775-- @treturn[2] string The reason the file could not be opened.\\\
776function open(filename, mode)\\\
777 expect(1, filename, \\\"string\\\")\\\
778 expect(2, mode, \\\"string\\\", \\\"nil\\\")\\\
779\\\
780 local sMode = mode and mode:gsub(\\\"%+\\\", \\\"\\\") or \\\"rb\\\"\\\
781 local file, err = fs.open(filename, sMode)\\\
782 if not file then return nil, err end\\\
783\\\
784 return make_file(file)\\\
785end\\\
786\\\
787--- Get or set the current output file.\\\
788--\\\
789-- @tparam[opt] Handle|string file The new output file, either as a file path or pre-existing handle.\\\
790-- @treturn Handle The current output file.\\\
791-- @throws If the provided filename cannot be opened for writing.\\\
792-- @since 1.55\\\
793function output(file)\\\
794 if type_of(file) == \\\"string\\\" then\\\
795 local res, err = open(file, \\\"wb\\\")\\\
796 if not res then error(err, 2) end\\\
797 currentOutput = res\\\
798 elseif type_of(file) == \\\"table\\\" and getmetatable(file) == handleMetatable then\\\
799 currentOutput = file\\\
800 elseif file ~= nil then\\\
801 error(\\\"bad argument #1 (FILE expected, got \\\" .. type_of(file) .. \\\")\\\", 2)\\\
802 end\\\
803\\\
804 return currentOutput\\\
805end\\\
806\\\
807--- Read from the currently opened input file.\\\
808--\\\
809-- This is equivalent to `io.input():read(...)`. See @{Handle:read|the\\\
810-- documentation} there for full details.\\\
811--\\\
812-- @tparam string ... The formats to read, defaulting to a whole line.\\\
813-- @treturn (string|nil)... The data read, or @{nil} if nothing can be read.\\\
814function read(...)\\\
815 return currentInput:read(...)\\\
816end\\\
817\\\
818--- Checks whether `handle` is a given file handle, and determine if it is open\\\
819-- or not.\\\
820--\\\
821-- @param obj The value to check\\\
822-- @treturn string|nil `\\\"file\\\"` if this is an open file, `\\\"closed file\\\"` if it\\\
823-- is a closed file handle, or `nil` if not a file handle.\\\
824function type(obj)\\\
825 if type_of(obj) == \\\"table\\\" and getmetatable(obj) == handleMetatable then\\\
826 if obj._closed then\\\
827 return \\\"closed file\\\"\\\
828 else\\\
829 return \\\"file\\\"\\\
830 end\\\
831 end\\\
832 return nil\\\
833end\\\
834\\\
835--- Write to the currently opened output file.\\\
836--\\\
837-- This is equivalent to `io.output():write(...)`. See @{Handle:write|the\\\
838-- documentation} there for full details.\\\
839--\\\
840-- @tparam string ... The strings to write\\\
841-- @changed 1.81.0 Multiple arguments are now allowed.\\\
842function write(...)\\\
843 return currentOutput:write(...)\\\
844end\\\
845\",\
846 Path = \"boot/apis/io.lua\",\
847 },\
848 {\
849 func = \"--- An API for advanced systems which can draw pixels and lines, load and draw\\\
850-- image files. You can use the `colors` API for easier color manipulation. In\\\
851-- CraftOS-PC, this API can also be used in graphics mode.\\\
852--\\\
853-- @module paintutils\\\
854-- @since 1.45\\\
855\\\
856local expect = os.dofile(\\\"rom/modules/main/cc/expect.lua\\\",_ENV).expect\\\
857\\\
858local function drawPixelInternal(xPos, yPos)\\\
859 if term.getGraphicsMode and term.getGraphicsMode() then\\\
860 term.setPixel(xPos - 1, yPos - 1, term.getBackgroundColor())\\\
861 else\\\
862 term.setCursorPos(xPos, yPos)\\\
863 term.write(\\\" \\\")\\\
864 end\\\
865end\\\
866\\\
867local tColourLookup = {}\\\
868for n = 1, 16 do\\\
869 tColourLookup[string.byte(\\\"0123456789abcdef\\\", n, n)] = 2 ^ (n - 1)\\\
870end\\\
871\\\
872local function parseLine(tImageArg, sLine)\\\
873 local tLine = {}\\\
874 for x = 1, sLine:len() do\\\
875 tLine[x] = tColourLookup[string.byte(sLine, x, x)] or 0\\\
876 end\\\
877 table.insert(tImageArg, tLine)\\\
878end\\\
879\\\
880-- Sorts pairs of startX/startY/endX/endY such that the start is always the min\\\
881local function sortCoords(startX, startY, endX, endY)\\\
882 local minX, maxX, minY, maxY\\\
883\\\
884 if startX <= endX then\\\
885 minX, maxX = startX, endX\\\
886 else\\\
887 minX, maxX = endX, startX\\\
888 end\\\
889\\\
890 if startY <= endY then\\\
891 minY, maxY = startY, endY\\\
892 else\\\
893 minY, maxY = endY, startY\\\
894 end\\\
895\\\
896 return minX, maxX, minY, maxY\\\
897end\\\
898\\\
899--- Parses an image from a multi-line string\\\
900--\\\
901-- @tparam string image The string containing the raw-image data.\\\
902-- @treturn table The parsed image data, suitable for use with\\\
903-- @{paintutils.drawImage}.\\\
904-- @since 1.80pr1\\\
905function parseImage(image)\\\
906 expect(1, image, \\\"string\\\")\\\
907 local tImage = {}\\\
908 for sLine in (image .. \\\"\\\\n\\\"):gmatch(\\\"(.-)\\\\n\\\") do\\\
909 parseLine(tImage, sLine)\\\
910 end\\\
911 return tImage\\\
912end\\\
913\\\
914--- Loads an image from a file.\\\
915--\\\
916-- You can create a file suitable for being loaded using the `paint` program.\\\
917--\\\
918-- @tparam string path The file to load.\\\
919--\\\
920-- @treturn table|nil The parsed image data, suitable for use with\\\
921-- @{paintutils.drawImage}, or `nil` if the file does not exist.\\\
922-- @usage Load an image and draw it.\\\
923--\\\
924-- local image = paintutils.loadImage(\\\"test-image.nfp\\\")\\\
925-- paintutils.drawImage(image, term.getCursorPos())\\\
926function loadImage(path)\\\
927 expect(1, path, \\\"string\\\")\\\
928\\\
929 if fs.exists(path) then\\\
930 local file = io.open(path, \\\"r\\\")\\\
931 local sContent = file:read(\\\"*a\\\")\\\
932 file:close()\\\
933 return parseImage(sContent)\\\
934 end\\\
935 return nil\\\
936end\\\
937\\\
938--- Draws a single pixel to the current term at the specified position.\\\
939--\\\
940-- Be warned, this may change the position of the cursor and the current\\\
941-- background colour. You should not expect either to be preserved.\\\
942--\\\
943-- @tparam number xPos The x position to draw at, where 1 is the far left.\\\
944-- @tparam number yPos The y position to draw at, where 1 is the very top.\\\
945-- @tparam[opt] number colour The @{colors|color} of this pixel. This will be\\\
946-- the current background colour if not specified.\\\
947function drawPixel(xPos, yPos, colour)\\\
948 expect(1, xPos, \\\"number\\\")\\\
949 expect(2, yPos, \\\"number\\\")\\\
950 expect(3, colour, \\\"number\\\", \\\"nil\\\")\\\
951\\\
952 if colour then\\\
953 term.setBackgroundColor(colour)\\\
954 end\\\
955 return drawPixelInternal(xPos, yPos)\\\
956end\\\
957\\\
958--- Draws a straight line from the start to end position.\\\
959--\\\
960-- Be warned, this may change the position of the cursor and the current\\\
961-- background colour. You should not expect either to be preserved.\\\
962--\\\
963-- @tparam number startX The starting x position of the line.\\\
964-- @tparam number startY The starting y position of the line.\\\
965-- @tparam number endX The end x position of the line.\\\
966-- @tparam number endY The end y position of the line.\\\
967-- @tparam[opt] number colour The @{colors|color} of this pixel. This will be\\\
968-- the current background colour if not specified.\\\
969-- @usage paintutils.drawLine(2, 3, 30, 7, colors.red)\\\
970function drawLine(startX, startY, endX, endY, colour)\\\
971 expect(1, startX, \\\"number\\\")\\\
972 expect(2, startY, \\\"number\\\")\\\
973 expect(3, endX, \\\"number\\\")\\\
974 expect(4, endY, \\\"number\\\")\\\
975 expect(5, colour, \\\"number\\\", \\\"nil\\\")\\\
976\\\
977 startX = math.floor(startX)\\\
978 startY = math.floor(startY)\\\
979 endX = math.floor(endX)\\\
980 endY = math.floor(endY)\\\
981\\\
982 if colour then\\\
983 term.setBackgroundColor(colour)\\\
984 end\\\
985 if startX == endX and startY == endY then\\\
986 drawPixelInternal(startX, startY)\\\
987 return\\\
988 end\\\
989\\\
990 local minX = math.min(startX, endX)\\\
991 local maxX, minY, maxY\\\
992 if minX == startX then\\\
993 minY = startY\\\
994 maxX = endX\\\
995 maxY = endY\\\
996 else\\\
997 minY = endY\\\
998 maxX = startX\\\
999 maxY = startY\\\
1000 end\\\
1001\\\
1002 -- TODO: clip to screen rectangle?\\\
1003\\\
1004 local xDiff = maxX - minX\\\
1005 local yDiff = maxY - minY\\\
1006\\\
1007 if xDiff > math.abs(yDiff) then\\\
1008 local y = minY\\\
1009 local dy = yDiff / xDiff\\\
1010 for x = minX, maxX do\\\
1011 drawPixelInternal(x, math.floor(y + 0.5))\\\
1012 y = y + dy\\\
1013 end\\\
1014 else\\\
1015 local x = minX\\\
1016 local dx = xDiff / yDiff\\\
1017 if maxY >= minY then\\\
1018 for y = minY, maxY do\\\
1019 drawPixelInternal(math.floor(x + 0.5), y)\\\
1020 x = x + dx\\\
1021 end\\\
1022 else\\\
1023 for y = minY, maxY, -1 do\\\
1024 drawPixelInternal(math.floor(x + 0.5), y)\\\
1025 x = x - dx\\\
1026 end\\\
1027 end\\\
1028 end\\\
1029end\\\
1030\\\
1031--- Draws the outline of a box on the current term from the specified start\\\
1032-- position to the specified end position.\\\
1033--\\\
1034-- Be warned, this may change the position of the cursor and the current\\\
1035-- background colour. You should not expect either to be preserved.\\\
1036--\\\
1037-- @tparam number startX The starting x position of the line.\\\
1038-- @tparam number startY The starting y position of the line.\\\
1039-- @tparam number endX The end x position of the line.\\\
1040-- @tparam number endY The end y position of the line.\\\
1041-- @tparam[opt] number colour The @{colors|color} of this pixel. This will be\\\
1042-- the current background colour if not specified.\\\
1043-- @usage paintutils.drawBox(2, 3, 30, 7, colors.red)\\\
1044function drawBox(startX, startY, endX, endY, nColour)\\\
1045 expect(1, startX, \\\"number\\\")\\\
1046 expect(2, startY, \\\"number\\\")\\\
1047 expect(3, endX, \\\"number\\\")\\\
1048 expect(4, endY, \\\"number\\\")\\\
1049 expect(5, nColour, \\\"number\\\", \\\"nil\\\")\\\
1050\\\
1051 startX = math.floor(startX)\\\
1052 startY = math.floor(startY)\\\
1053 endX = math.floor(endX)\\\
1054 endY = math.floor(endY)\\\
1055\\\
1056 if nColour then\\\
1057 term.setBackgroundColor(nColour) -- Maintain legacy behaviour\\\
1058 else\\\
1059 nColour = term.getBackgroundColour()\\\
1060 end\\\
1061\\\
1062 if term.getGraphicsMode and term.getGraphicsMode() then\\\
1063 local c, w, h = nColour or term.getBackgroundColor(), endX - startX, endY - startY\\\
1064 term.drawPixels(startX, startY, c, w, 1)\\\
1065 term.drawPixels(startX, startY, c, 1, h)\\\
1066 term.drawPixels(endX, startY+1, c, 1, h)\\\
1067 term.drawPixels(startX+1, endY, c, w, 1)\\\
1068 else\\\
1069 local colourHex = colours.toBlit(nColour)\\\
1070\\\
1071 if startX == endX and startY == endY then\\\
1072 drawPixelInternal(startX, startY)\\\
1073 return\\\
1074 end\\\
1075\\\
1076 local minX, maxX, minY, maxY = sortCoords(startX, startY, endX, endY)\\\
1077 local width = maxX - minX + 1\\\
1078\\\
1079 for y = minY, maxY do\\\
1080 if y == minY or y == maxY then\\\
1081 term.setCursorPos(minX, y)\\\
1082 term.blit((\\\" \\\"):rep(width), colourHex:rep(width), colourHex:rep(width))\\\
1083 else\\\
1084 term.setCursorPos(minX, y)\\\
1085 term.blit(\\\" \\\", colourHex, colourHex)\\\
1086 term.setCursorPos(maxX, y)\\\
1087 term.blit(\\\" \\\", colourHex, colourHex)\\\
1088 end\\\
1089 end\\\
1090 end\\\
1091end\\\
1092\\\
1093--- Draws a filled box on the current term from the specified start position to\\\
1094-- the specified end position.\\\
1095--\\\
1096-- Be warned, this may change the position of the cursor and the current\\\
1097-- background colour. You should not expect either to be preserved.\\\
1098--\\\
1099-- @tparam number startX The starting x position of the line.\\\
1100-- @tparam number startY The starting y position of the line.\\\
1101-- @tparam number endX The end x position of the line.\\\
1102-- @tparam number endY The end y position of the line.\\\
1103-- @tparam[opt] number colour The @{colors|color} of this pixel. This will be\\\
1104-- the current background colour if not specified.\\\
1105-- @usage paintutils.drawFilledBox(2, 3, 30, 7, colors.red)\\\
1106function drawFilledBox(startX, startY, endX, endY, nColour)\\\
1107 expect(1, startX, \\\"number\\\")\\\
1108 expect(2, startY, \\\"number\\\")\\\
1109 expect(3, endX, \\\"number\\\")\\\
1110 expect(4, endY, \\\"number\\\")\\\
1111 expect(5, nColour, \\\"number\\\", \\\"nil\\\")\\\
1112\\\
1113 startX = math.floor(startX)\\\
1114 startY = math.floor(startY)\\\
1115 endX = math.floor(endX)\\\
1116 endY = math.floor(endY)\\\
1117\\\
1118 if nColour then\\\
1119 term.setBackgroundColor(nColour) -- Maintain legacy behaviour\\\
1120 else\\\
1121 nColour = term.getBackgroundColour()\\\
1122 end\\\
1123\\\
1124 if term.getGraphicsMode and term.getGraphicsMode() then\\\
1125 local c = nColour or term.getBackgroundColor()\\\
1126 term.drawPixels(startX, startY, c, endX - startX, endY - startY)\\\
1127 else\\\
1128 local colourHex = colours.toBlit(nColour)\\\
1129\\\
1130 if startX == endX and startY == endY then\\\
1131 drawPixelInternal(startX, startY)\\\
1132 return\\\
1133 end\\\
1134\\\
1135 local minX, maxX, minY, maxY = sortCoords(startX, startY, endX, endY)\\\
1136 local width = maxX - minX + 1\\\
1137\\\
1138 for y = minY, maxY do\\\
1139 term.setCursorPos(minX, y)\\\
1140 term.blit((\\\" \\\"):rep(width), colourHex:rep(width), colourHex:rep(width))\\\
1141 end\\\
1142 end\\\
1143end\\\
1144\\\
1145--- Draw an image loaded by @{paintutils.parseImage} or @{paintutils.loadImage}.\\\
1146--\\\
1147-- @tparam table image The parsed image data.\\\
1148-- @tparam number xPos The x position to start drawing at.\\\
1149-- @tparam number yPos The y position to start drawing at.\\\
1150function drawImage(image, xPos, yPos)\\\
1151 expect(1, image, \\\"table\\\")\\\
1152 expect(2, xPos, \\\"number\\\")\\\
1153 expect(3, yPos, \\\"number\\\")\\\
1154 for y = 1, #image do\\\
1155 local tLine = image[y]\\\
1156 for x = 1, #tLine do\\\
1157 if tLine[x] > 0 then\\\
1158 term.setBackgroundColor(tLine[x])\\\
1159 drawPixelInternal(x + xPos - 1, y + yPos - 1)\\\
1160 end\\\
1161 end\\\
1162 end\\\
1163end\\\
1164\",\
1165 Path = \"boot/apis/paintutils.lua\",\
1166 },\
1167 {\
1168 func = \"--- The settings API allows to store values and save them to a file for\\\
1169-- persistent configurations for CraftOS and your programs.\\\
1170--\\\
1171-- By default, the settings API will load its configuration from the\\\
1172-- `/.settings` file. One can then use @{settings.save} to update the file.\\\
1173--\\\
1174-- @module settings\\\
1175-- @since 1.78\\\
1176\\\
1177local expect = os.dofile(\\\"rom/modules/main/cc/expect.lua\\\")\\\
1178local textutils = os.dofile(\\\"boot/modules/strings.lua\\\")\\\
1179local type, expect, field = type, expect.expect, expect.field\\\
1180\\\
1181local details, values = {}, {}\\\
1182\\\
1183local function reserialize(value)\\\
1184 if type(value) ~= \\\"table\\\" then return value end\\\
1185 return textutils.unserialize(textutils.serialize(value))\\\
1186end\\\
1187\\\
1188local function copy(value)\\\
1189 if type(value) ~= \\\"table\\\" then return value end\\\
1190 local result = {}\\\
1191 for k, v in pairs(value) do result[k] = copy(v) end\\\
1192 return result\\\
1193end\\\
1194\\\
1195local valid_types = { \\\"number\\\", \\\"string\\\", \\\"boolean\\\", \\\"table\\\" }\\\
1196for _, v in ipairs(valid_types) do valid_types[v] = true end\\\
1197\\\
1198--- Define a new setting, optional specifying various properties about it.\\\
1199--\\\
1200-- While settings do not have to be added before being used, doing so allows\\\
1201-- you to provide defaults and additional metadata.\\\
1202--\\\
1203-- @tparam string name The name of this option\\\
1204-- @tparam[opt] { description? = string, default? = any, type? = string } options\\\
1205-- Options for this setting. This table accepts the following fields:\\\
1206--\\\
1207-- - `description`: A description which may be printed when running the `set` program.\\\
1208-- - `default`: A default value, which is returned by @{settings.get} if the\\\
1209-- setting has not been changed.\\\
1210-- - `type`: Require values to be of this type. @{set|Setting} the value to another type\\\
1211-- will error.\\\
1212-- @since 1.87.0\\\
1213function define(name, options)\\\
1214 expect(1, name, \\\"string\\\")\\\
1215 expect(2, options, \\\"table\\\", \\\"nil\\\")\\\
1216\\\
1217 if options then\\\
1218 options = {\\\
1219 description = field(options, \\\"description\\\", \\\"string\\\", \\\"nil\\\"),\\\
1220 default = reserialize(field(options, \\\"default\\\", \\\"number\\\", \\\"string\\\", \\\"boolean\\\", \\\"table\\\", \\\"nil\\\")),\\\
1221 type = field(options, \\\"type\\\", \\\"string\\\", \\\"nil\\\"),\\\
1222 }\\\
1223\\\
1224 if options.type and not valid_types[options.type] then\\\
1225 error((\\\"Unknown type %q. Expected one of %s.\\\"):format(options.type, table.concat(valid_types, \\\", \\\")), 2)\\\
1226 end\\\
1227 else\\\
1228 options = {}\\\
1229 end\\\
1230\\\
1231 details[name] = options\\\
1232end\\\
1233\\\
1234--- Remove a @{define|definition} of a setting.\\\
1235--\\\
1236-- If a setting has been changed, this does not remove its value. Use @{settings.unset}\\\
1237-- for that.\\\
1238--\\\
1239-- @tparam string name The name of this option\\\
1240-- @since 1.87.0\\\
1241function undefine(name)\\\
1242 expect(1, name, \\\"string\\\")\\\
1243 details[name] = nil\\\
1244end\\\
1245\\\
1246local function set_value(name, value)\\\
1247 local new = reserialize(value)\\\
1248 local old = values[name]\\\
1249 if old == nil then\\\
1250 local opt = details[name]\\\
1251 old = opt and opt.default\\\
1252 end\\\
1253\\\
1254 values[name] = new\\\
1255 if old ~= new then\\\
1256 -- This should be safe, as os.queueEvent copies values anyway.\\\
1257 os.queueEvent(\\\"setting_changed\\\", name, new, old)\\\
1258 end\\\
1259end\\\
1260\\\
1261--- Set the value of a setting.\\\
1262--\\\
1263-- @tparam string name The name of the setting to set\\\
1264-- @param value The setting's value. This cannot be `nil`, and must be\\\
1265-- serialisable by @{textutils.serialize}.\\\
1266-- @throws If this value cannot be serialised\\\
1267-- @see settings.unset\\\
1268function set(name, value)\\\
1269 expect(1, name, \\\"string\\\")\\\
1270 expect(2, value, \\\"number\\\", \\\"string\\\", \\\"boolean\\\", \\\"table\\\")\\\
1271\\\
1272 local opt = details[name]\\\
1273 if opt and opt.type then expect(2, value, opt.type) end\\\
1274\\\
1275 set_value(name, value)\\\
1276end\\\
1277\\\
1278--- Get the value of a setting.\\\
1279--\\\
1280-- @tparam string name The name of the setting to get.\\\
1281-- @param[opt] default The value to use should there be pre-existing value for\\\
1282-- this setting. If not given, it will use the setting's default value if given,\\\
1283-- or `nil` otherwise.\\\
1284-- @return The setting's, or the default if the setting has not been changed.\\\
1285-- @changed 1.87.0 Now respects default value if pre-defined and `default` is unset.\\\
1286function get(name, default)\\\
1287 expect(1, name, \\\"string\\\")\\\
1288 local result = values[name]\\\
1289 if result ~= nil then\\\
1290 return copy(result)\\\
1291 elseif default ~= nil then\\\
1292 return default\\\
1293 else\\\
1294 local opt = details[name]\\\
1295 return opt and copy(opt.default)\\\
1296 end\\\
1297end\\\
1298\\\
1299--- Get details about a specific setting.\\\
1300--\\\
1301-- @tparam string name The name of the setting to get.\\\
1302-- @treturn { description? = string, default? = any, type? = string, value? = any }\\\
1303-- Information about this setting. This includes all information from @{settings.define},\\\
1304-- as well as this setting's value.\\\
1305-- @since 1.87.0\\\
1306function getDetails(name)\\\
1307 expect(1, name, \\\"string\\\")\\\
1308 local deets = copy(details[name]) or {}\\\
1309 deets.value = values[name]\\\
1310 deets.changed = deets.value ~= nil\\\
1311 if deets.value == nil then deets.value = deets.default end\\\
1312 return deets\\\
1313end\\\
1314\\\
1315--- Remove the value of a setting, setting it to the default.\\\
1316--\\\
1317-- @{settings.get} will return the default value until the setting's value is\\\
1318-- @{settings.set|set}, or the computer is rebooted.\\\
1319--\\\
1320-- @tparam string name The name of the setting to unset.\\\
1321-- @see settings.set\\\
1322-- @see settings.clear\\\
1323function unset(name)\\\
1324 expect(1, name, \\\"string\\\")\\\
1325 set_value(name, nil)\\\
1326end\\\
1327\\\
1328--- Resets the value of all settings. Equivalent to calling @{settings.unset}\\\
1329--- on every setting.\\\
1330--\\\
1331-- @see settings.unset\\\
1332function clear()\\\
1333 for name in pairs(values) do\\\
1334 set_value(name, nil)\\\
1335 end\\\
1336end\\\
1337\\\
1338--- Get the names of all currently defined settings.\\\
1339--\\\
1340-- @treturn { string } An alphabetically sorted list of all currently-defined\\\
1341-- settings.\\\
1342function getNames()\\\
1343 local result, n = {}, 1\\\
1344 for k in pairs(details) do\\\
1345 result[n], n = k, n + 1\\\
1346 end\\\
1347 for k in pairs(values) do\\\
1348 if not details[k] then result[n], n = k, n + 1 end\\\
1349 end\\\
1350 table.sort(result)\\\
1351 return result\\\
1352end\\\
1353\\\
1354--- Load settings from the given file.\\\
1355--\\\
1356-- Existing settings will be merged with any pre-existing ones. Conflicting\\\
1357-- entries will be overwritten, but any others will be preserved.\\\
1358--\\\
1359-- @tparam[opt] string sPath The file to load from, defaulting to `.settings`.\\\
1360-- @treturn boolean Whether settings were successfully read from this\\\
1361-- file. Reasons for failure may include the file not existing or being\\\
1362-- corrupted.\\\
1363--\\\
1364-- @see settings.save\\\
1365-- @changed 1.87.0 `sPath` is now optional.\\\
1366function load(sPath)\\\
1367 expect(1, sPath, \\\"string\\\", \\\"nil\\\")\\\
1368 local file = fs.open(sPath or \\\".settings\\\", \\\"r\\\")\\\
1369 if not file then\\\
1370 return false\\\
1371 end\\\
1372\\\
1373 local sText = file.readAll()\\\
1374 file.close()\\\
1375\\\
1376 local tFile = textutils.unserialize(sText)\\\
1377 if type(tFile) ~= \\\"table\\\" then\\\
1378 return false\\\
1379 end\\\
1380\\\
1381 for k, v in pairs(tFile) do\\\
1382 local ty_v = type(v)\\\
1383 if type(k) == \\\"string\\\" and (ty_v == \\\"string\\\" or ty_v == \\\"number\\\" or ty_v == \\\"boolean\\\" or ty_v == \\\"table\\\") then\\\
1384 local opt = details[k]\\\
1385 if not opt or not opt.type or ty_v == opt.type then\\\
1386 set_value(k, v)\\\
1387 end\\\
1388 end\\\
1389 end\\\
1390\\\
1391 return true\\\
1392end\\\
1393\\\
1394--- Save settings to the given file.\\\
1395--\\\
1396-- This will entirely overwrite the pre-existing file. Settings defined in the\\\
1397-- file, but not currently loaded will be removed.\\\
1398--\\\
1399-- @tparam[opt] string sPath The path to save settings to, defaulting to `.settings`.\\\
1400-- @treturn boolean If the settings were successfully saved.\\\
1401--\\\
1402-- @see settings.load\\\
1403-- @changed 1.87.0 `sPath` is now optional.\\\
1404function save(sPath)\\\
1405 expect(1, sPath, \\\"string\\\", \\\"nil\\\")\\\
1406 local file = fs.open(sPath or \\\".settings\\\", \\\"w\\\")\\\
1407 if not file then\\\
1408 return false\\\
1409 end\\\
1410\\\
1411 file.write(textutils.serialize(values))\\\
1412 file.close()\\\
1413\\\
1414 return true\\\
1415end\\\
1416\",\
1417 Path = \"boot/apis/settings.lua\",\
1418 },\
1419 {\
1420 func = \"\\\
1421local term = term\\\
1422local table = table\\\
1423local coroutine = coroutine\\\
1424local debug = debug\\\
1425local fs = fs\\\
1426local os = os\\\
1427local type = type\\\
1428local pcall = pcall\\\
1429local errhandle = error\\\
1430local type = type\\\
1431local nativeload = load\\\
1432local nativeloadstring = loadstring\\\
1433local nativesetfenv = setfenv\\\
1434local nativereboot = os.reboot or reboot or function () os.shutdown(true) end\\\
1435local nativeshutdown = os.shutdown or shutdown\\\
1436local boot = true\\\
1437local expect\\\
1438do\\\
1439 local h = fs.open(\\\"rom/modules/main/cc/expect.lua\\\", \\\"r\\\")\\\
1440 local f, err = (_VERSION == \\\"Lua 5.1\\\" and loadstring or load)(h.readAll(), \\\"@expect.lua\\\")\\\
1441 h.close()\\\
1442\\\
1443 if not f then error(err) end\\\
1444 expect = f().expect\\\
1445end\\\
1446local util\\\
1447do\\\
1448 local h = fs.open(\\\"boot/modules/utilties.lua\\\", \\\"r\\\")\\\
1449 local f, err = (_VERSION == \\\"Lua 5.1\\\" and loadstring or load)(h.readAll(), \\\"@utilties.lua\\\")\\\
1450 h.close()\\\
1451 if not f then error(err) end\\\
1452 util = f()\\\
1453end\\\
1454_G.native = {}\\\
1455util.table.copy(_G.native,_G)\\\
1456term.setCursorBlink(false)\\\
1457_G.logs = function (_sDir)\\\
1458 if not fs.isDir(_sDir) and fs.exists(_sDir)\\\
1459 then\\\
1460 error((\\\"%s:is not a directory\\\"):format(_sDir))\\\
1461 end\\\
1462 return function (name)\\\
1463 local Path\\\
1464 name = util.file.withoutExtension(fs.getName(name))\\\
1465 if fs.exists((\\\"%s/%s.log\\\"):format(_sDir,name))\\\
1466 then\\\
1467 local i = 0\\\
1468 repeat\\\
1469 i = i+1\\\
1470 until not fs.exists((\\\"%s/%s(%s).log\\\"):format(_sDir,name,i))\\\
1471 Path = (\\\"%s/%s(%s).log\\\"):format(_sDir,name,i)\\\
1472 else\\\
1473 Path = (\\\"%s/%s.log\\\"):format(_sDir,name)\\\
1474 end\\\
1475 local file = fs.open(Path,\\\"w\\\")\\\
1476 local handle = {}\\\
1477 function handle.info(info)\\\
1478 expect(1,info,\\\"string\\\")\\\
1479 file.write((\\\"info:%s:%s \\\\n\\\"):format(os.date(),info))\\\
1480 end\\\
1481 function handle.warn(warn)\\\
1482 expect(1,warn,\\\"string\\\")\\\
1483 file.write((\\\"warn:%s:%s \\\\n\\\"):format(os.date(),warn))\\\
1484 end\\\
1485 function handle.error(err)\\\
1486 expect(1,err,\\\"string\\\")\\\
1487 file.write((\\\"error:%s:%s \\\\n\\\"):format(os.date(),err))\\\
1488 end\\\
1489 function handle.critical(crit)\\\
1490 expect(1,crit,\\\"string\\\")\\\
1491 file.write((\\\"critical:%s:%s \\\\n\\\"):format(os.date(),crit))\\\
1492 end\\\
1493 function handle.close()\\\
1494 file.close()\\\
1495 end\\\
1496 return handle\\\
1497 end\\\
1498end\\\
1499local bootseqfunc = logs(\\\"boot/logs\\\")\\\
1500local bootseq = bootseqfunc(\\\"bios\\\")\\\
1501bootseq.info(\\\"starting up...\\\")\\\
1502\\\
1503_G.error = function (mess,level)\\\
1504 expect(1,mess,\\\"string\\\")\\\
1505 expect(2,level,\\\"number\\\",\\\"nil\\\")\\\
1506 if level and level ~= 0 \\\
1507 then\\\
1508 level = level +1\\\
1509 else\\\
1510 level = 4\\\
1511 end\\\
1512 if boot\\\
1513 then\\\
1514 bootseq.close()\\\
1515 boot = false\\\
1516 end\\\
1517 errhandle(mess,level or 0)\\\
1518end\\\
1519-- Historically load/loadstring would handle the chunk name as if it has\\\
1520-- been prefixed with \\\"=\\\". We emulate that behaviour here.\\\
1521local function prefix(chunkname)\\\
1522 if type(chunkname) ~= \\\"string\\\" then return chunkname end\\\
1523 local head = chunkname:sub(1, 1)\\\
1524 if head == \\\"=\\\" or head == \\\"@\\\" then\\\
1525 return chunkname\\\
1526 else\\\
1527 return \\\"=\\\" .. chunkname\\\
1528 end\\\
1529end\\\
1530if _VERSION == \\\"Lua 5.1\\\" then\\\
1531 -- 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\\\
1532 function os.load(x, name, mode, env)\\\
1533 expect(1, x, \\\"function\\\", \\\"string\\\")\\\
1534 expect(2, name, \\\"string\\\", \\\"nil\\\")\\\
1535 expect(3, mode, \\\"string\\\", \\\"nil\\\")\\\
1536 expect(4, env, \\\"table\\\", \\\"nil\\\")\\\
1537 if boot\\\
1538 then\\\
1539 bootseq.info(\\\"loading : \\\"..name)\\\
1540 end\\\
1541 local ok, p1, p2 = pcall(function()\\\
1542 if type(x) == \\\"string\\\" then\\\
1543 local bool,result = pcall(nativeloadstring,x, name)\\\
1544 if bool then\\\
1545 if env then\\\
1546 env._ENV = env\\\
1547 nativesetfenv(result, env)\\\
1548 end\\\
1549 return result\\\
1550 else\\\
1551 return nil,result\\\
1552 end\\\
1553 else\\\
1554 local bool,result = pcall(nativeload,x, name)\\\
1555 if bool then\\\
1556 if env then\\\
1557 env._ENV = env\\\
1558 nativesetfenv(result, env)\\\
1559 end\\\
1560 return result\\\
1561 else\\\
1562 return nil,result\\\
1563 end\\\
1564 end\\\
1565 end)\\\
1566 if ok then\\\
1567 return p1, p2\\\
1568 else\\\
1569 error(p1, 2)\\\
1570 end\\\
1571 end\\\
1572 if _CC_DISABLE_LUA51_FEATURES then\\\
1573 -- Remove the Lua 5.1 features that will be removed when we update to Lua 5.2, for compatibility testing.\\\
1574 -- See \\\"disable_lua51_functions\\\" in ComputerCraft.cfg\\\
1575 setfenv = nil\\\
1576 getfenv = nil\\\
1577 loadstring = nil\\\
1578 unpack = nil\\\
1579 math.log10 = nil\\\
1580 table.maxn = nil\\\
1581 else\\\
1582 os.loadstring = function(string, chunkname) return nativeloadstring(string, prefix(chunkname)) end\\\
1583 -- Inject a stub for the old bit library\\\
1584 _G.bit = {\\\
1585 bnot = bit32.bnot,\\\
1586 band = bit32.band,\\\
1587 bor = bit32.bor,\\\
1588 bxor = bit32.bxor,\\\
1589 brshift = bit32.arshift,\\\
1590 blshift = bit32.lshift,\\\
1591 blogic_rshift = bit32.rshift,\\\
1592 }\\\
1593 end\\\
1594elseif not _CC_DISABLE_LUA51_FEATURES then\\\
1595 os.load = load\\\
1596 -- Restore old Lua 5.1 functions for compatibility\\\
1597 -- setfenv/getfenv replacements from https://leafo.net/guides/setfenv-in-lua52-and-above.html\\\
1598 function setfenv(fn, env)\\\
1599 if not debug then error(\\\"could not set environment\\\", 2) end\\\
1600 local i = 1\\\
1601 while true do\\\
1602 local name = debug.getupvalue(fn, i)\\\
1603 if name == \\\"_ENV\\\" then\\\
1604 debug.upvaluejoin(fn, i, (function()\\\
1605 return env\\\
1606 end), 1)\\\
1607 break\\\
1608 elseif not name then\\\
1609 break\\\
1610 end\\\
1611\\\
1612 i = i + 1\\\
1613 end\\\
1614\\\
1615 return fn\\\
1616 end\\\
1617\\\
1618 function getfenv(fn)\\\
1619 local i = 1\\\
1620 while true do\\\
1621 local name, val = debug.getupvalue(fn, i)\\\
1622 if name == \\\"_ENV\\\" then\\\
1623 return val\\\
1624 elseif not name then\\\
1625 break\\\
1626 end\\\
1627 i = i + 1\\\
1628 end\\\
1629 end\\\
1630\\\
1631 function table.maxn(tab)\\\
1632 return tab.n or #tab\\\
1633 end\\\
1634 math.log10 = function(x) return math.log(x, 10) end\\\
1635 os.loadstring = function(string, chunkname) return os.load(string, prefix(chunkname)) end\\\
1636 unpack = table.unpack\\\
1637\\\
1638 -- Inject a stub for the old bit library\\\
1639 _G.bit = {\\\
1640 bnot = bit32.bnot,\\\
1641 band = bit32.band,\\\
1642 bor = bit32.bor,\\\
1643 bxor = bit32.bxor,\\\
1644 brshift = bit32.arshift,\\\
1645 blshift = bit32.lshift,\\\
1646 blogic_rshift = bit32.rshift,\\\
1647 }\\\
1648end\\\
1649-- Install lua parts of the os api\\\
1650function os.version()\\\
1651 return \\\"bios-CC_Tweaked v1\\\"\\\
1652end\\\
1653\\\
1654function os.pullEventRaw(sFilter)\\\
1655 return coroutine.yield(sFilter)\\\
1656end\\\
1657\\\
1658function os.pullEvent(sFilter)\\\
1659 local eventData = table.pack(coroutine.yield(sFilter))\\\
1660 if eventData[1] == \\\"terminate\\\" then\\\
1661 error(\\\"Terminated\\\", 0)\\\
1662 end\\\
1663 return table.unpack(eventData, 1, eventData.n)\\\
1664end\\\
1665\\\
1666function os.sleep(nTime)\\\
1667 expect(1, nTime, \\\"number\\\", \\\"nil\\\")\\\
1668 local timer = os.startTimer(nTime or 0)\\\
1669 repeat\\\
1670 local _, param = os.pullEvent(\\\"timer\\\")\\\
1671 until param == timer\\\
1672end \\\
1673function os.loadfile(filename, mode, env)\\\
1674 -- Support the previous `loadfile(filename, env)` form instead.\\\
1675 if type(mode) == \\\"table\\\" and env == nil then\\\
1676 mode, env = nil, mode\\\
1677 end\\\
1678\\\
1679 expect(1, filename, \\\"string\\\")\\\
1680 expect(2, mode, \\\"string\\\", \\\"nil\\\")\\\
1681 expect(3, env, \\\"table\\\", \\\"nil\\\")\\\
1682\\\
1683 local file = fs.open(filename, \\\"r\\\")\\\
1684 if not file then\\\
1685 if boot then\\\
1686 bootseq.critical((\\\"%s:not found\\\"):format(filename))\\\
1687 end\\\
1688 return nil, \\\"File not found\\\"\\\
1689 end \\\
1690 local func, err = os.load(file.readAll(), \\\"@\\\" .. filename, mode, env)\\\
1691 file.close()\\\
1692 if not func and boot then\\\
1693 bootseq.critical((\\\"%s:not found\\\"):format(filename))\\\
1694 error(err,0)\\\
1695 elseif not func\\\
1696 then\\\
1697 error(err,0)\\\
1698 end\\\
1699 return func, err\\\
1700end\\\
1701\\\
1702function os.dofile(_sFile,_Env)\\\
1703 expect(1, _sFile, \\\"string\\\")\\\
1704 expect(2,_Env,\\\"table\\\",\\\"nil\\\")\\\
1705 _Env = setmetatable(_Env or {},{__index = _G})\\\
1706 local fnFile, e = os.loadfile(_sFile, nil, _Env)\\\
1707 if fnFile then\\\
1708 return fnFile()\\\
1709 else\\\
1710 if boot\\\
1711 then\\\
1712 bootseq.critical((\\\"%s,%s\\\"):format(_sFile,e))\\\
1713 end\\\
1714 error(e, 2)\\\
1715 end\\\
1716end\\\
1717local output = os.dofile(\\\"boot/modules/output.lua\\\",_ENV)\\\
1718local tAPIsLoading = {}\\\
1719function os.loadAPI(_sPath,_env)\\\
1720 expect(1, _sPath, \\\"string\\\")\\\
1721 expect(2,_env,\\\"table\\\",\\\"nil\\\")\\\
1722 local sName = fs.getName(_sPath)\\\
1723 if sName:sub(-4) == \\\".lua\\\" then\\\
1724 sName = sName:sub(1, -5)\\\
1725 end\\\
1726 if tAPIsLoading[sName] == true then\\\
1727 output.printError(\\\"API \\\" .. sName .. \\\" is already being loaded\\\")\\\
1728 return false\\\
1729 end\\\
1730 tAPIsLoading[sName] = true\\\
1731 local tEnv = _env or {}\\\
1732 setmetatable(tEnv, { __index = _G })\\\
1733 local fnAPI, err = os.loadfile(_sPath, nil, tEnv)\\\
1734 if fnAPI then\\\
1735 local ok, err = pcall(fnAPI)\\\
1736 if not ok then\\\
1737 tAPIsLoading[sName] = nil\\\
1738 if boot\\\
1739 then\\\
1740 bootseq.info(\\\"Failed to load API \\\" .. sName .. \\\" due to \\\" .. err)\\\
1741 end\\\
1742 return error(\\\"Failed to load API \\\" .. sName .. \\\" due to \\\" .. err, 1)\\\
1743 end\\\
1744 else\\\
1745 tAPIsLoading[sName] = nil\\\
1746 if boot\\\
1747 then\\\
1748 bootseq.info(\\\"Failed to load API \\\" .. sName .. \\\" due to \\\" .. err)\\\
1749 end\\\
1750 return error(\\\"Failed to load API \\\" .. sName .. \\\" due to \\\" .. err, 1)\\\
1751 end\\\
1752\\\
1753 local tAPI = {}\\\
1754 for k, v in pairs(tEnv) do\\\
1755 if k ~= \\\"_ENV\\\" then\\\
1756 tAPI[k] = v\\\
1757 end\\\
1758 end\\\
1759\\\
1760 _G[sName] = tAPI\\\
1761 tAPIsLoading[sName] = nil\\\
1762 return true\\\
1763end\\\
1764os.loadAPI(\\\"rom/apis/keys.lua\\\",setmetatable({[\\\"dofile\\\"] = os.dofile},{__index = _G}))\\\
1765local function load_apis(dir)\\\
1766 if not fs.isDir(dir) then return end\\\
1767 for _, file in ipairs(fs.list(dir)) do\\\
1768 if file:sub(1, 1) ~= \\\".\\\" then\\\
1769 local path = fs.combine(dir, file)\\\
1770 if not fs.isDir(path) then\\\
1771 os.loadAPI(path)\\\
1772 end\\\
1773 end\\\
1774 end\\\
1775end\\\
1776load_apis(\\\"boot/apis\\\")\\\
1777function os.unloadAPI(_sName)\\\
1778 expect(1, _sName, \\\"string\\\")\\\
1779 if _sName ~= \\\"_G\\\" and type(_G[_sName]) == \\\"table\\\" then\\\
1780 _G[_sName] = nil\\\
1781 end\\\
1782end\\\
1783local input = os.dofile(\\\"boot/modules/input.lua\\\",_ENV)\\\
1784function os.run(_tEnv, _sPath, ...)\\\
1785 expect(1, _tEnv, \\\"table\\\")\\\
1786 expect(2, _sPath, \\\"string\\\")\\\
1787\\\
1788 local tEnv = _tEnv\\\
1789 setmetatable(tEnv, { __index = _G })\\\
1790 local fnFile, err = os.loadfile(_sPath, nil, tEnv)\\\
1791 if fnFile then\\\
1792 local ok = table.pack(pcall(fnFile, ...))\\\
1793 if not ok[1] then\\\
1794 if ok[2] and ok[2] ~= \\\"\\\" then\\\
1795 output.printError(ok[2])\\\
1796 end\\\
1797 return false,table.unpack(ok,2)\\\
1798 end\\\
1799 return true,table.unpack(ok,2)\\\
1800 end\\\
1801 if err and err ~= \\\"\\\" then\\\
1802 output.printError(err)\\\
1803 end\\\
1804 return false,err\\\
1805end\\\
1806os.shutdown = function (m)\\\
1807 bootseq.close()\\\
1808 if m\\\
1809 then\\\
1810 nativereboot()\\\
1811 else\\\
1812 nativeshutdown()\\\
1813 end\\\
1814 while true do\\\
1815 coroutine.yield()\\\
1816 end\\\
1817end\\\
1818os.reboot = function ()\\\
1819 os.shutdown(true)\\\
1820end\\\
1821-- boot loader finder code\\\
1822local pullEvent = os.pullEvent\\\
1823local function allowTerminate(Lbool)\\\
1824 expect(1,Lbool,\\\"boolean\\\")\\\
1825 if Lbool then\\\
1826 os.pullEvent = pullEvent\\\
1827 else\\\
1828 os.pullEvent = os.pullEventRaw\\\
1829 end\\\
1830end\\\
1831local parallel = os.dofile(\\\"boot/modules/parallel.lua\\\",_ENV)\\\
1832allowTerminate(false)\\\
1833local switch,debugging = false,false\\\
1834local nativeTerm = term\\\
1835local run = true\\\
1836local function prompt(message)\\\
1837 expect(1,message,\\\"string\\\",\\\"nil\\\")\\\
1838 local x,_ = term.getCursorPos()\\\
1839 output.print(message)\\\
1840 local _,y2 = term.getCursorPos()\\\
1841 term.setCursorPos(x,y2)\\\
1842 return tostring(input.read())\\\
1843end\\\
1844local function BasicMenu(Table,mess,optionsColor,TextColor,BackgroundColor)\\\
1845 expect(1,Table,\\\"table\\\")\\\
1846 expect(2,mess,\\\"string\\\")\\\
1847 expect(3,optionsColor,\\\"number\\\",\\\"nil\\\")\\\
1848 expect(4,TextColor,\\\"number\\\",\\\"nil\\\")\\\
1849 expect(5,BackgroundColor,\\\"number\\\",\\\"nil\\\")\\\
1850 optionsColor = optionsColor or colors.white\\\
1851 TextColor = TextColor or colors.white\\\
1852 BackgroundColor = BackgroundColor or colors.green\\\
1853 local Sx = term.getSize()\\\
1854 local originalBack = term.getBackgroundColor()\\\
1855 local originalText = term.getTextColor()\\\
1856 local run = true\\\
1857 local sel = 1\\\
1858 while run do\\\
1859 term.setBackgroundColor(BackgroundColor)\\\
1860 term.clear()\\\
1861 term.setCursorPos(math.ceil(( Sx / 2) - (mess:len() / 2)),1)\\\
1862 output.print(mess)\\\
1863 for _=0,Sx do\\\
1864 term.write(\\\"=\\\")\\\
1865 end\\\
1866 local _,Current = term.getCursorPos()\\\
1867 term.setCursorPos(0,Current+1)\\\
1868 for i,v in pairs(Table) do\\\
1869 local _,y2 = term.getCursorPos()\\\
1870 if sel == i\\\
1871 then\\\
1872 local stri = (\\\"[%s]:%s\\\"):format(i,v)\\\
1873 term.setCursorPos(math.ceil((Sx / 2) - (stri:len() / 2)),y2)\\\
1874 term.setTextColor(optionsColor)\\\
1875 output.print(stri)\\\
1876 term.setTextColor(TextColor)\\\
1877 else\\\
1878 local stri = (\\\"%s:%s\\\"):format(i,v)\\\
1879 term.setCursorPos(math.ceil((Sx / 2) - (stri:len() / 2)),y2)\\\
1880 term.setTextColor(optionsColor)\\\
1881 output.print(stri)\\\
1882 term.setTextColor(TextColor)\\\
1883 end\\\
1884 end\\\
1885 local _,key = os.pullEvent(\\\"key\\\")\\\
1886 if key == keys.up and sel>1\\\
1887 then\\\
1888 sel = sel-1\\\
1889 elseif key == keys.down and sel<#Table\\\
1890 then\\\
1891 sel = sel+1\\\
1892 elseif key == keys.enter\\\
1893 then\\\
1894 term.setBackgroundColor(originalBack)\\\
1895 term.setTextColor(originalText)\\\
1896 term.clear()\\\
1897 term.setCursorPos(1,1)\\\
1898 return sel\\\
1899 end\\\
1900 end\\\
1901end\\\
1902\\\
1903if fs.exists(\\\"boot/boot.settings\\\")\\\
1904then\\\
1905 settings.load(\\\"boot/boot.settings\\\")\\\
1906end\\\
1907local pin = settings.get(\\\"boot.pin\\\")\\\
1908local Load = settings.get(\\\"boot.Load\\\")\\\
1909local setMode = false\\\
1910if not pin\\\
1911then\\\
1912 parallel.waitForAny(\\\
1913 function ()\\\
1914 if BasicMenu({\\\"yes\\\",\\\"no\\\"},\\\"set up pin?\\\") == 1\\\
1915 then\\\
1916 setMode = true\\\
1917 end\\\
1918 end,\\\
1919 function ()\\\
1920 os.sleep(2)\\\
1921 term.setBackgroundColor(colors.black)\\\
1922 term.setTextColor(colors.white)\\\
1923 term.clear()\\\
1924 term.setCursorPos(1,1)\\\
1925 end\\\
1926 )\\\
1927end\\\
1928if setMode\\\
1929then\\\
1930 pin = tostring(prompt(\\\"set pin\\\"))\\\
1931 settings.define(\\\"boot.pin\\\",{description = \\\"stores the current bios pin\\\", default = nil, type = \\\"string\\\"})\\\
1932 settings.set(\\\"boot.pin\\\",pin)\\\
1933 term.clear()\\\
1934end\\\
1935parallel.waitForAny(\\\
1936 function ()\\\
1937 term.clear()\\\
1938 term.setCursorPos(1,1)\\\
1939 output.print(\\\"hit f4 to select boot mode or hit enter\\\")\\\
1940 term.setCursorPos(1,3)\\\
1941 if fs.exists(\\\"boot/Image.nfp\\\")\\\
1942 then\\\
1943 paintutils.drawImage(paintutils.loadImage(\\\"boot/Image.nfp\\\"),1,1)\\\
1944 term.setBackgroundColor(colors.black)\\\
1945 end\\\
1946 while run do\\\
1947 local _,num = os.pullEvent(\\\"key\\\")\\\
1948 if num == keys.f4\\\
1949 then\\\
1950 switch = true\\\
1951 run = false\\\
1952 elseif num == keys.enter\\\
1953 then\\\
1954 term.clear()\\\
1955 term.setCursorPos(1,1)\\\
1956 run = false\\\
1957 end\\\
1958 end\\\
1959 end,\\\
1960 function ()\\\
1961 os.sleep(3)\\\
1962 term.clear()\\\
1963 term.setCursorPos(1,1)\\\
1964 end\\\
1965)\\\
1966term.clear()\\\
1967if switch or Load == nil or not fs.exists(Load)\\\
1968then\\\
1969 if pin and Load\\\
1970 then\\\
1971 term.clear()\\\
1972 term.setCursorPos(1,1)\\\
1973 if tostring(prompt(\\\"pin?\\\")) ~= pin\\\
1974 then\\\
1975 output.printError(\\\"wrong pin : press any key to continue\\\")\\\
1976 os.pullEvent(\\\"key\\\")\\\
1977 os.reboot()\\\
1978 end\\\
1979 end\\\
1980 local Table = fs.list(\\\"\\\")\\\
1981 for i,v in pairs(Table) do\\\
1982 if v == \\\"rom\\\"\\\
1983 then\\\
1984 table.remove(Table,i)\\\
1985 end\\\
1986 end\\\
1987 local list = {}\\\
1988 for _,v in pairs(Table) do\\\
1989 if fs.isDir(v) then\\\
1990 local list2 = fs.find(fs.combine(v,\\\"*\\\"))\\\
1991 for _,b in pairs(list2) do\\\
1992 if fs.isDir(b)\\\
1993 then\\\
1994 table.insert(Table,b)\\\
1995 else\\\
1996 table.insert(list,b)\\\
1997 end\\\
1998 end\\\
1999 else\\\
2000 table.insert(list,v)\\\
2001 end\\\
2002 end\\\
2003 local OS = {}\\\
2004 for _,v in pairs(list) do\\\
2005 if string.find(v,\\\"OS.boot\\\")\\\
2006 then\\\
2007 table.insert(OS,v)\\\
2008 end\\\
2009 end\\\
2010 if #OS >1\\\
2011 then\\\
2012 local i = BasicMenu(OS,\\\"choose OS\\\")\\\
2013 Load = OS[i]\\\
2014 else\\\
2015 Load = OS[1] or output.printError(\\\"no bootloader found\\\")\\\
2016 if Load == nil\\\
2017 then\\\
2018 os.pullEvent(\\\"char\\\")\\\
2019 os.shutdown()\\\
2020 end\\\
2021 end\\\
2022 settings.set(\\\"boot.Load\\\",Load)\\\
2023 debugging = (BasicMenu({\\\"no\\\",\\\"yes\\\"},(\\\"put %s into debug mode\\\"):format(fs.getName(Load))) == 2)\\\
2024end\\\
2025local Func,err = os.loadfile(Load,\\\"bt\\\",setmetatable({},{__index = _G}))\\\
2026if not Func then\\\
2027 settings.unset(\\\"boot.Load\\\")\\\
2028 nativeTerm.setBackgroundColor(colors.blue)\\\
2029 nativeTerm.setTextColor(colors.white)\\\
2030 nativeTerm.clear()\\\
2031 nativeTerm.setCursorPos(1,1)\\\
2032 local x,_ = nativeTerm.getSize()\\\
2033 for _ = 0 ,x do\\\
2034 nativeTerm.write(\\\"=\\\")\\\
2035 end\\\
2036 nativeTerm.setTextColor(colors.red)\\\
2037 output.printError((\\\"%s : reseted Load settings\\\"):format(err))\\\
2038 local _,y = nativeTerm.getCursorPos()\\\
2039 nativeTerm.setCursorPos(1,y)\\\
2040 nativeTerm.setTextColor(colors.white)\\\
2041 for _ = 0 ,x do\\\
2042 nativeTerm.write(\\\"=\\\")\\\
2043 end\\\
2044 os.pullEvent(\\\"char\\\")\\\
2045 os.reboot()\\\
2046 error(\\\"\\\",0)\\\
2047end\\\
2048settings.save(\\\"boot/boot.settings\\\")\\\
2049allowTerminate(true)\\\
2050boot = false\\\
2051local bool,err = pcall(Func,debugging)\\\
2052boot = true\\\
2053allowTerminate(false)\\\
2054if not bool\\\
2055then\\\
2056 nativeTerm.setBackgroundColor(colors.blue)\\\
2057 nativeTerm.setTextColor(colors.white)\\\
2058 nativeTerm.clear()\\\
2059 nativeTerm.setCursorPos(1,1)\\\
2060 local x,_ = nativeTerm.getSize()\\\
2061 for _ = 0 ,x do\\\
2062 nativeTerm.write(\\\"=\\\")\\\
2063 end\\\
2064 nativeTerm.setTextColor(colors.red)\\\
2065 output.printError(err)\\\
2066 local _,y = nativeTerm.getCursorPos()\\\
2067 nativeTerm.setCursorPos(1,y)\\\
2068 nativeTerm.setTextColor(colors.white)\\\
2069 for _ = 0 ,x do\\\
2070 nativeTerm.write(\\\"=\\\")\\\
2071 end\\\
2072 os.pullEvent(\\\"char\\\")\\\
2073 os.reboot()\\\
2074end\",\
2075 Path = \"boot/bios.lua\",\
2076 },\
2077 {\
2078 func = \"{}\",\
2079 Path = \"boot/boot.settings\",\
2080 },\
2081 {\
2082 func = \"local handle = {}\\\
2083local output = (require and require(\\\"boot.modules.output\\\") or os.dofile(\\\"boot/modules/output.lua\\\",_ENV))\\\
2084local expect = (require and require (\\\"cc.expect\\\") or os.dofile(\\\"rom/modules/main/cc/expect.lua\\\",_ENV)).expect\\\
2085function handle.read(_sReplaceChar, _tHistory, _fnComplete, _sDefault)\\\
2086 expect(1, _sReplaceChar, \\\"string\\\", \\\"nil\\\")\\\
2087 expect(2, _tHistory, \\\"table\\\", \\\"nil\\\")\\\
2088 expect(3, _fnComplete, \\\"function\\\", \\\"nil\\\")\\\
2089 expect(4, _sDefault, \\\"string\\\", \\\"nil\\\")\\\
2090\\\
2091 term.setCursorBlink(true)\\\
2092\\\
2093 local sLine\\\
2094 if type(_sDefault) == \\\"string\\\" then\\\
2095 sLine = _sDefault\\\
2096 else\\\
2097 sLine = \\\"\\\"\\\
2098 end\\\
2099 local nHistoryPos\\\
2100 local nPos, nScroll = #sLine, 0\\\
2101 if _sReplaceChar then\\\
2102 _sReplaceChar = string.sub(_sReplaceChar, 1, 1)\\\
2103 end\\\
2104\\\
2105 local tCompletions\\\
2106 local nCompletion\\\
2107 local function recomplete()\\\
2108 if _fnComplete and nPos == #sLine then\\\
2109 tCompletions = _fnComplete(sLine)\\\
2110 if tCompletions and #tCompletions > 0 then\\\
2111 nCompletion = 1\\\
2112 else\\\
2113 nCompletion = nil\\\
2114 end\\\
2115 else\\\
2116 tCompletions = nil\\\
2117 nCompletion = nil\\\
2118 end\\\
2119 end\\\
2120\\\
2121 local function uncomplete()\\\
2122 tCompletions = nil\\\
2123 nCompletion = nil\\\
2124 end\\\
2125\\\
2126 local w = term.getSize()\\\
2127 local sx = term.getCursorPos()\\\
2128\\\
2129 local function redraw(_bClear)\\\
2130 local cursor_pos = nPos - nScroll\\\
2131 if sx + cursor_pos >= w then\\\
2132 -- We've moved beyond the RHS, ensure we're on the edge.\\\
2133 nScroll = sx + nPos - w\\\
2134 elseif cursor_pos < 0 then\\\
2135 -- We've moved beyond the LHS, ensure we're on the edge.\\\
2136 nScroll = nPos\\\
2137 end\\\
2138\\\
2139 local _, cy = term.getCursorPos()\\\
2140 term.setCursorPos(sx, cy)\\\
2141 local sReplace = _bClear and \\\" \\\" or _sReplaceChar\\\
2142 if sReplace then\\\
2143 term.write(string.rep(sReplace, math.max(#sLine - nScroll, 0)))\\\
2144 else\\\
2145 term.write(string.sub(sLine, nScroll + 1))\\\
2146 end\\\
2147\\\
2148 if nCompletion then\\\
2149 local sCompletion = tCompletions[nCompletion]\\\
2150 local oldText, oldBg\\\
2151 if not _bClear then\\\
2152 oldText = term.getTextColor()\\\
2153 oldBg = term.getBackgroundColor()\\\
2154 term.setTextColor(colors.white)\\\
2155 term.setBackgroundColor(colors.gray)\\\
2156 end\\\
2157 if sReplace then\\\
2158 term.write(string.rep(sReplace, #sCompletion))\\\
2159 else\\\
2160 term.write(sCompletion)\\\
2161 end\\\
2162 if not _bClear then\\\
2163 term.setTextColor(oldText)\\\
2164 term.setBackgroundColor(oldBg)\\\
2165 end\\\
2166 end\\\
2167\\\
2168 term.setCursorPos(sx + nPos - nScroll, cy)\\\
2169 end\\\
2170\\\
2171 local function clear()\\\
2172 redraw(true)\\\
2173 end\\\
2174\\\
2175 recomplete()\\\
2176 redraw()\\\
2177\\\
2178 local function acceptCompletion()\\\
2179 if nCompletion then\\\
2180 -- Clear\\\
2181 clear()\\\
2182\\\
2183 -- Find the common prefix of all the other suggestions which start with the same letter as the current one\\\
2184 local sCompletion = tCompletions[nCompletion]\\\
2185 sLine = sLine .. sCompletion\\\
2186 nPos = #sLine\\\
2187\\\
2188 -- Redraw\\\
2189 recomplete()\\\
2190 redraw()\\\
2191 end\\\
2192 end\\\
2193 while true do\\\
2194 local sEvent, param, param1, param2 = os.pullEvent()\\\
2195 if sEvent == \\\"char\\\" then\\\
2196 -- Typed key\\\
2197 clear()\\\
2198 sLine = string.sub(sLine, 1, nPos) .. param .. string.sub(sLine, nPos + 1)\\\
2199 nPos = nPos + 1\\\
2200 recomplete()\\\
2201 redraw()\\\
2202\\\
2203 elseif sEvent == \\\"paste\\\" then\\\
2204 -- Pasted text\\\
2205 clear()\\\
2206 sLine = string.sub(sLine, 1, nPos) .. param .. string.sub(sLine, nPos + 1)\\\
2207 nPos = nPos + #param\\\
2208 recomplete()\\\
2209 redraw()\\\
2210\\\
2211 elseif sEvent == \\\"key\\\" then\\\
2212 if param == keys.enter or param == keys.numPadEnter then\\\
2213 -- Enter/Numpad Enter\\\
2214 if nCompletion then\\\
2215 clear()\\\
2216 uncomplete()\\\
2217 redraw()\\\
2218 end\\\
2219 break\\\
2220\\\
2221 elseif param == keys.left then\\\
2222 -- Left\\\
2223 if nPos > 0 then\\\
2224 clear()\\\
2225 nPos = nPos - 1\\\
2226 recomplete()\\\
2227 redraw()\\\
2228 end\\\
2229\\\
2230 elseif param == keys.right then\\\
2231 -- Right\\\
2232 if nPos < #sLine then\\\
2233 -- Move right\\\
2234 clear()\\\
2235 nPos = nPos + 1\\\
2236 recomplete()\\\
2237 redraw()\\\
2238 else\\\
2239 -- Accept autocomplete\\\
2240 acceptCompletion()\\\
2241 end\\\
2242\\\
2243 elseif param == keys.up or param == keys.down then\\\
2244 -- Up or down\\\
2245 if nCompletion then\\\
2246 -- Cycle completions\\\
2247 clear()\\\
2248 if param == keys.up then\\\
2249 nCompletion = nCompletion - 1\\\
2250 if nCompletion < 1 then\\\
2251 nCompletion = #tCompletions\\\
2252 end\\\
2253 elseif param == keys.down then\\\
2254 nCompletion = nCompletion + 1\\\
2255 if nCompletion > #tCompletions then\\\
2256 nCompletion = 1\\\
2257 end\\\
2258 end\\\
2259 redraw()\\\
2260\\\
2261 elseif _tHistory then\\\
2262 -- Cycle history\\\
2263 clear()\\\
2264 if param == keys.up then\\\
2265 -- Up\\\
2266 if nHistoryPos == nil then\\\
2267 if #_tHistory > 0 then\\\
2268 nHistoryPos = #_tHistory\\\
2269 end\\\
2270 elseif nHistoryPos > 1 then\\\
2271 nHistoryPos = nHistoryPos - 1\\\
2272 end\\\
2273 else\\\
2274 -- Down\\\
2275 if nHistoryPos == #_tHistory then\\\
2276 nHistoryPos = nil\\\
2277 elseif nHistoryPos ~= nil then\\\
2278 nHistoryPos = nHistoryPos + 1\\\
2279 end\\\
2280 end\\\
2281 if nHistoryPos then\\\
2282 sLine = _tHistory[nHistoryPos]\\\
2283 nPos, nScroll = #sLine, 0\\\
2284 else\\\
2285 sLine = \\\"\\\"\\\
2286 nPos, nScroll = 0, 0\\\
2287 end\\\
2288 uncomplete()\\\
2289 redraw()\\\
2290\\\
2291 end\\\
2292\\\
2293 elseif param == keys.backspace then\\\
2294 -- Backspace\\\
2295 if nPos > 0 then\\\
2296 clear()\\\
2297 sLine = string.sub(sLine, 1, nPos - 1) .. string.sub(sLine, nPos + 1)\\\
2298 nPos = nPos - 1\\\
2299 if nScroll > 0 then nScroll = nScroll - 1 end\\\
2300 recomplete()\\\
2301 redraw()\\\
2302 end\\\
2303\\\
2304 elseif param == keys.home then\\\
2305 -- Home\\\
2306 if nPos > 0 then\\\
2307 clear()\\\
2308 nPos = 0\\\
2309 recomplete()\\\
2310 redraw()\\\
2311 end\\\
2312\\\
2313 elseif param == keys.delete then\\\
2314 -- Delete\\\
2315 if nPos < #sLine then\\\
2316 clear()\\\
2317 sLine = string.sub(sLine, 1, nPos) .. string.sub(sLine, nPos + 2)\\\
2318 recomplete()\\\
2319 redraw()\\\
2320 end\\\
2321\\\
2322 elseif param == keys[\\\"end\\\"] then\\\
2323 -- End\\\
2324 if nPos < #sLine then\\\
2325 clear()\\\
2326 nPos = #sLine\\\
2327 recomplete()\\\
2328 redraw()\\\
2329 end\\\
2330\\\
2331 elseif param == keys.tab then\\\
2332 -- Tab (accept autocomplete)\\\
2333 acceptCompletion()\\\
2334\\\
2335 end\\\
2336\\\
2337 elseif sEvent == \\\"mouse_click\\\" or sEvent == \\\"mouse_drag\\\" and param == 1 then\\\
2338 local _, cy = term.getCursorPos()\\\
2339 if param1 >= sx and param1 <= w and param2 == cy then\\\
2340 -- Ensure we don't scroll beyond the current line\\\
2341 nPos = math.min(math.max(nScroll + param1 - sx, 0), #sLine)\\\
2342 redraw()\\\
2343 end\\\
2344\\\
2345 elseif sEvent == \\\"term_resize\\\" then\\\
2346 -- Terminal resized\\\
2347 w = term.getSize()\\\
2348 redraw()\\\
2349\\\
2350 end\\\
2351 end\\\
2352\\\
2353 local _, cy = term.getCursorPos()\\\
2354 term.setCursorBlink(false)\\\
2355 term.setCursorPos(w + 1, cy)\\\
2356 output.print()\\\
2357\\\
2358 return sLine\\\
2359end\\\
2360return handle\",\
2361 Path = \"boot/modules/input.lua\",\
2362 },\
2363 {\
2364 func = \"local handle = {}\\\
2365local expect = (require and require (\\\"cc.expect\\\") or os.dofile(\\\"rom/modules/main/cc/expect.lua\\\",_ENV))\\\
2366local wrap = ((require and require(\\\"modules.strings\\\")) or os.dofile(\\\"rom/modules/main/cc/strings.lua\\\",{[\\\"dofile\\\"] = os.dofile})).wrap\\\
2367local field,range = expect.field,expect.range\\\
2368expect = expect.expect\\\
2369local function makePagedScroll(_term, _nFreeLines)\\\
2370 local nativeScroll = _term.scroll\\\
2371 local nFreeLines = _nFreeLines or 0\\\
2372 return function(_n)\\\
2373 for _ = 1, _n do\\\
2374 nativeScroll(1)\\\
2375 if nFreeLines <= 0 then\\\
2376 local _, h = _term.getSize()\\\
2377 _term.setCursorPos(1, h)\\\
2378 _term.write(\\\"Press any key to continue\\\")\\\
2379 os.pullEvent(\\\"key\\\")\\\
2380 _term.clearLine()\\\
2381 _term.setCursorPos(1, h)\\\
2382 else\\\
2383 nFreeLines = nFreeLines - 1\\\
2384 end\\\
2385 end\\\
2386 end\\\
2387end\\\
2388function handle.write(sText)\\\
2389 expect(1, sText, \\\"string\\\", \\\"number\\\")\\\
2390 local w, h = term.getSize()\\\
2391 local x, y = term.getCursorPos()\\\
2392\\\
2393 local nLinesPrinted = 0\\\
2394 local function newLine()\\\
2395 if y + 1 <= h then\\\
2396 term.setCursorPos(1, y + 1)\\\
2397 else\\\
2398 term.setCursorPos(1, h)\\\
2399 term.scroll(1)\\\
2400 end\\\
2401 x, y = term.getCursorPos()\\\
2402 nLinesPrinted = nLinesPrinted + 1\\\
2403 end\\\
2404\\\
2405 -- Print the line with proper word wrapping\\\
2406 sText = tostring(sText)\\\
2407 while #sText > 0 do\\\
2408 local whitespace = string.match(sText, \\\"^[ \\\\t]+\\\")\\\
2409 if whitespace then\\\
2410 -- Print whitespace\\\
2411 term.write(whitespace)\\\
2412 x, y = term.getCursorPos()\\\
2413 sText = string.sub(sText, #whitespace + 1)\\\
2414 end\\\
2415\\\
2416 local newline = string.match(sText, \\\"^\\\\n\\\")\\\
2417 if newline then\\\
2418 -- Print newlines\\\
2419 newLine()\\\
2420 sText = string.sub(sText, 2)\\\
2421 end\\\
2422\\\
2423 local text = string.match(sText, \\\"^[^ \\\\t\\\\n]+\\\")\\\
2424 if text then\\\
2425 sText = string.sub(sText, #text + 1)\\\
2426 if #text > w then\\\
2427 -- Print a multiline word\\\
2428 while #text > 0 do\\\
2429 if x > w then\\\
2430 newLine()\\\
2431 end\\\
2432 term.write(text)\\\
2433 text = string.sub(text, w - x + 2)\\\
2434 x, y = term.getCursorPos()\\\
2435 end\\\
2436 else\\\
2437 -- Print a word normally\\\
2438 if x + #text - 1 > w then\\\
2439 newLine()\\\
2440 end\\\
2441 term.write(text)\\\
2442 x, y = term.getCursorPos()\\\
2443 end\\\
2444 end\\\
2445 end\\\
2446\\\
2447 return nLinesPrinted\\\
2448end\\\
2449function handle.print(...)\\\
2450 local nLinesPrinted = 0\\\
2451 local nLimit = select(\\\"#\\\", ...)\\\
2452 for n = 1, nLimit do\\\
2453 local s = tostring(select(n, ...))\\\
2454 if n < nLimit then\\\
2455 s = s .. \\\"\\\\t\\\"\\\
2456 end\\\
2457 nLinesPrinted = nLinesPrinted + handle.write(s)\\\
2458 end\\\
2459 nLinesPrinted = nLinesPrinted + handle.write(\\\"\\\\n\\\")\\\
2460 return nLinesPrinted\\\
2461end\\\
2462\\\
2463function handle.printError(...)\\\
2464 local oldColour\\\
2465 if term.isColour() then\\\
2466 oldColour = term.getTextColour()\\\
2467 term.setTextColour(colors.red)\\\
2468 end\\\
2469 handle.print(...)\\\
2470 if term.isColour() then\\\
2471 term.setTextColour(oldColour)\\\
2472 end\\\
2473end\\\
2474\\\
2475--- Slowly writes string text at current cursor position,\\\
2476-- character-by-character.\\\
2477--\\\
2478-- Like @{_G.write}, this does not insert a newline at the end.\\\
2479--\\\
2480-- @tparam string text The the text to write to the screen\\\
2481-- @tparam[opt] number rate The number of characters to write each second,\\\
2482-- Defaults to 20.\\\
2483-- @usage textutils.slowWrite(\\\"Hello, world!\\\")\\\
2484-- @usage textutils.slowWrite(\\\"Hello, world!\\\", 5)\\\
2485-- @since 1.3\\\
2486function handle.slowWrite(text, rate)\\\
2487 expect(2, rate, \\\"number\\\", \\\"nil\\\")\\\
2488 rate = rate or 20\\\
2489 if rate < 0 then\\\
2490 error(\\\"Rate must be positive\\\", 2)\\\
2491 end\\\
2492 local to_sleep = 1 / rate\\\
2493\\\
2494 local wrapped_lines = wrap(tostring(text), (term.getSize()))\\\
2495 local wrapped_str = table.concat(wrapped_lines, \\\"\\\\n\\\")\\\
2496\\\
2497 for n = 1, #wrapped_str do\\\
2498 os.sleep(to_sleep)\\\
2499 handle.write(wrapped_str:sub(n, n))\\\
2500 end\\\
2501end\\\
2502\\\
2503--- Slowly prints string text at current cursor position,\\\
2504-- character-by-character.\\\
2505--\\\
2506-- Like @{print}, this inserts a newline after printing.\\\
2507--\\\
2508-- @tparam string sText The the text to write to the screen\\\
2509-- @tparam[opt] number nRate The number of characters to write each second,\\\
2510-- Defaults to 20.\\\
2511-- @usage textutils.slowPrint(\\\"Hello, world!\\\")\\\
2512-- @usage textutils.slowPrint(\\\"Hello, world!\\\", 5)\\\
2513function handle.slowPrint(sText, nRate)\\\
2514 handle.slowWrite(sText, nRate)\\\
2515 handle.print()\\\
2516end\\\
2517\\\
2518--[[- Prints a given string to the display.\\\
2519\\\
2520If the action can be completed without scrolling, it acts much the same as\\\
2521@{print}; otherwise, it will throw up a \\\"Press any key to continue\\\" prompt at\\\
2522the bottom of the display. Each press will cause it to scroll down and write a\\\
2523single line more before prompting again, if need be.\\\
2524\\\
2525@tparam string text The text to print to the screen.\\\
2526@tparam[opt] number free_lines The number of lines which will be\\\
2527automatically scrolled before the first prompt appears (meaning free_lines +\\\
25281 lines will be printed). This can be set to the cursor's y position - 2 to\\\
2529always try to fill the screen. Defaults to 0, meaning only one line is\\\
2530displayed before prompting.\\\
2531@treturn number The number of lines printed.\\\
2532\\\
2533@usage Generates several lines of text and then prints it, paging once the\\\
2534bottom of the terminal is reached.\\\
2535\\\
2536 local lines = {}\\\
2537 for i = 1, 30 do lines[i] = (\\\"This is line #%d\\\"):format(i) end\\\
2538 local message = table.concat(lines, \\\"\\\\n\\\")\\\
2539\\\
2540 local width, height = term.getCursorPos()\\\
2541 textutils.pagedPrint(message, height - 2)\\\
2542]]\\\
2543function handle.pagedPrint(text, free_lines)\\\
2544 expect(2, free_lines, \\\"number\\\", \\\"nil\\\")\\\
2545 -- Setup a redirector\\\
2546 local oldTerm = term.current()\\\
2547 local newTerm = {}\\\
2548 for k, v in pairs(oldTerm) do\\\
2549 newTerm[k] = v\\\
2550 end\\\
2551 newTerm.scroll = makePagedScroll(oldTerm, free_lines)\\\
2552 term.redirect(newTerm)\\\
2553\\\
2554 -- Print the text\\\
2555 local result\\\
2556 local ok, err = pcall(function()\\\
2557 if text ~= nil then\\\
2558 result = print(text)\\\
2559 else\\\
2560 result = print()\\\
2561 end\\\
2562 end)\\\
2563\\\
2564 -- Removed the redirector\\\
2565 term.redirect(oldTerm)\\\
2566\\\
2567 -- Propogate errors\\\
2568 if not ok then\\\
2569 error(err, 0)\\\
2570 end\\\
2571 return result\\\
2572end\\\
2573\\\
2574return handle\\\
2575\\\
2576\",\
2577 Path = \"boot/modules/output.lua\",\
2578 },\
2579 {\
2580 func = \"--[[- Provides a simple implementation of multitasking.\\\
2581\\\
2582Functions are not actually executed simultaniously, but rather this API will\\\
2583automatically switch between them whenever they yield (eg whenever they call\\\
2584@{coroutine.yield}, or functions that call that - eg @{os.pullEvent} - or\\\
2585functions that call that, etc - basically, anything that causes the function\\\
2586to \\\"pause\\\").\\\
2587\\\
2588Each function executed in \\\"parallel\\\" gets its own copy of the event queue,\\\
2589and so \\\"event consuming\\\" functions (again, mostly anything that causes the\\\
2590script to pause - eg @{sleep}, @{rednet.receive}, most of the @{turtle} API,\\\
2591etc) can safely be used in one without affecting the event queue accessed by\\\
2592the other.\\\
2593\\\
2594@module parallel\\\
2595@since 1.2\\\
2596]]\\\
2597local handle = {}\\\
2598local coroutine = coroutine\\\
2599local table = table\\\
2600local function create(...)\\\
2601 local tFns = table.pack(...)\\\
2602 local tCos = {}\\\
2603 for i = 1, tFns.n, 1 do\\\
2604 local fn = tFns[i]\\\
2605 if type(fn) ~= \\\"function\\\" then\\\
2606 error(\\\"bad argument #\\\" .. i .. \\\" (expected function, got \\\" .. type(fn) .. \\\")\\\", 3)\\\
2607 end\\\
2608\\\
2609 tCos[i] = coroutine.create(fn)\\\
2610 end\\\
2611\\\
2612 return tCos\\\
2613end\\\
2614\\\
2615local function runUntilLimit(_routines, _limit)\\\
2616 local count = #_routines\\\
2617 if count < 1 then return 0 end\\\
2618 local living = count\\\
2619\\\
2620 local tFilters = {}\\\
2621 local eventData = { n = 0 }\\\
2622 while true do\\\
2623 for n = 1, count do\\\
2624 local r = _routines[n]\\\
2625 if r then\\\
2626 if tFilters[r] == nil or tFilters[r] == eventData[1] or eventData[1] == \\\"terminate\\\" then\\\
2627 local ok, param = coroutine.resume(r, table.unpack(eventData, 1, eventData.n))\\\
2628 if not ok then\\\
2629 error(param, 0)\\\
2630 else\\\
2631 tFilters[r] = param\\\
2632 end\\\
2633 if coroutine.status(r) == \\\"dead\\\" then\\\
2634 _routines[n] = nil\\\
2635 living = living - 1\\\
2636 if living <= _limit then\\\
2637 return n\\\
2638 end\\\
2639 end\\\
2640 end\\\
2641 end\\\
2642 end\\\
2643 for n = 1, count do\\\
2644 local r = _routines[n]\\\
2645 if r and coroutine.status(r) == \\\"dead\\\" then\\\
2646 _routines[n] = nil\\\
2647 living = living - 1\\\
2648 if living <= _limit then\\\
2649 return n\\\
2650 end\\\
2651 end\\\
2652 end\\\
2653 eventData = table.pack(os.pullEventRaw())\\\
2654 end\\\
2655end\\\
2656\\\
2657--[[- Switches between execution of the functions, until any of them\\\
2658finishes. If any of the functions errors, the message is propagated upwards\\\
2659from the @{parallel.waitForAny} call.\\\
2660\\\
2661@tparam function ... The functions this task will run\\\
2662@usage Print a message every second until the `q` key is pressed.\\\
2663\\\
2664 local function tick()\\\
2665 while true do\\\
2666 os.sleep(1)\\\
2667 print(\\\"Tick\\\")\\\
2668 end\\\
2669 end\\\
2670 local function wait_for_q()\\\
2671 repeat\\\
2672 local _, key = os.pullEvent(\\\"key\\\")\\\
2673 until key == keys.q\\\
2674 print(\\\"Q was pressed!\\\")\\\
2675 end\\\
2676\\\
2677 parallel.waitForAny(tick, wait_for_q)\\\
2678 print(\\\"Everything done!\\\")\\\
2679]]\\\
2680function handle.waitForAny(...)\\\
2681 local routines = create(...)\\\
2682 return runUntilLimit(routines, #routines - 1)\\\
2683end\\\
2684\\\
2685--[[- Switches between execution of the functions, until all of them are\\\
2686finished. If any of the functions errors, the message is propagated upwards\\\
2687from the @{parallel.waitForAll} call.\\\
2688\\\
2689@tparam function ... The functions this task will run\\\
2690@usage Start off two timers and wait for them both to run.\\\
2691\\\
2692 local function a()\\\
2693 os.sleep(1)\\\
2694 print(\\\"A is done\\\")\\\
2695 end\\\
2696 local function b()\\\
2697 os.sleep(3)\\\
2698 print(\\\"B is done\\\")\\\
2699 end\\\
2700\\\
2701 parallel.waitForAll(a, b)\\\
2702 print(\\\"Everything done!\\\")\\\
2703]]\\\
2704function handle.waitForAll(...)\\\
2705 local routines = create(...)\\\
2706 return runUntilLimit(routines, 0)\\\
2707end\\\
2708return handle\\\
2709\",\
2710 Path = \"boot/modules/parallel.lua\",\
2711 },\
2712 {\
2713 func = \"local expect = ((require and require(\\\"cc.expect\\\")) or os.dofile(\\\"rom/modules/main/cc/expect.lua\\\",_ENV))\\\
2714local field,range = expect.field,expect.range\\\
2715expect = expect.expect\\\
2716local handle = {}\\\
2717\\\
2718--[[- Wraps a block of text, so that each line fits within the given width.\\\
2719\\\
2720This may be useful if you want to wrap text before displaying it to a\\\
2721@{monitor} or @{printer} without using @{_G.print|print}.\\\
2722\\\
2723@tparam string text The string to wrap.\\\
2724@tparam[opt] number width The width to constrain to, defaults to the width of\\\
2725the terminal.\\\
2726@treturn { string... } The wrapped input string as a list of lines.\\\
2727@usage Wrap a string and write it to the terminal.\\\
2728\\\
2729 term.clear()\\\
2730 local lines = require \\\"cc.strings\\\".wrap(\\\"This is a long piece of text\\\", 10)\\\
2731 for i = 1, #lines do\\\
2732 term.setCursorPos(1, i)\\\
2733 term.write(lines[i])\\\
2734 end\\\
2735]]\\\
2736function handle.wrap(text, width)\\\
2737 expect(1, text, \\\"string\\\")\\\
2738 expect(2, width, \\\"number\\\", \\\"nil\\\")\\\
2739 width = width or term.getSize()\\\
2740\\\
2741\\\
2742 local lines, lines_n, current_line = {}, 0, \\\"\\\"\\\
2743 local function push_line()\\\
2744 lines_n = lines_n + 1\\\
2745 lines[lines_n] = current_line\\\
2746 current_line = \\\"\\\"\\\
2747 end\\\
2748\\\
2749 local pos, length = 1, #text\\\
2750 local sub, match = string.sub, string.match\\\
2751 while pos <= length do\\\
2752 local head = sub(text, pos, pos)\\\
2753 if head == \\\" \\\" or head == \\\"\\\\t\\\" then\\\
2754 local whitespace = match(text, \\\"^[ \\\\t]+\\\", pos)\\\
2755 current_line = current_line .. whitespace\\\
2756 pos = pos + #whitespace\\\
2757 elseif head == \\\"\\\\n\\\" then\\\
2758 push_line()\\\
2759 pos = pos + 1\\\
2760 else\\\
2761 local word = match(text, \\\"^[^ \\\\t\\\\n]+\\\", pos)\\\
2762 pos = pos + #word\\\
2763 if #word > width then\\\
2764 -- Print a multiline word\\\
2765 while #word > 0 do\\\
2766 local space_remaining = width - #current_line - 1\\\
2767 if space_remaining <= 0 then\\\
2768 push_line()\\\
2769 space_remaining = width\\\
2770 end\\\
2771\\\
2772 current_line = current_line .. sub(word, 1, space_remaining)\\\
2773 word = sub(word, space_remaining + 1)\\\
2774 end\\\
2775 else\\\
2776 -- Print a word normally\\\
2777 if width - #current_line < #word then push_line() end\\\
2778 current_line = current_line .. word\\\
2779 end\\\
2780 end\\\
2781 end\\\
2782\\\
2783 push_line()\\\
2784\\\
2785 -- Trim whitespace longer than width.\\\
2786 for k, line in pairs(lines) do\\\
2787 line = line:sub(1, width)\\\
2788 lines[k] = line\\\
2789 end\\\
2790\\\
2791 return lines\\\
2792end\\\
2793\\\
2794--- Makes the input string a fixed width. This either truncates it, or pads it\\\
2795-- with spaces.\\\
2796--\\\
2797-- @tparam string line The string to normalise.\\\
2798-- @tparam[opt] number width The width to constrain to, defaults to the width of\\\
2799-- the terminal.\\\
2800--\\\
2801-- @treturn string The string with a specific width.\\\
2802-- @usage require \\\"cc.strings\\\".ensure_width(\\\"a short string\\\", 20)\\\
2803-- @usage require \\\"cc.strings\\\".ensure_width(\\\"a rather long string which is truncated\\\", 20)\\\
2804function handle.ensure_width(line, width)\\\
2805 expect(1, line, \\\"string\\\")\\\
2806 expect(2, width, \\\"number\\\", \\\"nil\\\")\\\
2807 width = width or term.getSize()\\\
2808\\\
2809 line = line:sub(1, width)\\\
2810 if #line < width then\\\
2811 line = line .. (\\\" \\\"):rep(width - #line)\\\
2812 end\\\
2813\\\
2814 return line\\\
2815end\\\
2816\\\
2817\\\
2818--- Takes input time and formats it in a more readable format such as `6:30 PM`.\\\
2819--\\\
2820-- @tparam number nTime The time to format, as provided by @{os.time}.\\\
2821-- @tparam[opt] boolean bTwentyFourHour Whether to format this as a 24-hour\\\
2822-- clock (`18:30`) rather than a 12-hour one (`6:30 AM`)\\\
2823-- @treturn string The formatted time\\\
2824-- @usage Print the current in-game time as a 12-hour clock.\\\
2825--\\\
2826-- textutils.formatTime(os.time())\\\
2827-- @usage Print the local time as a 24-hour clock.\\\
2828--\\\
2829-- textutils.formatTime(os.time(\\\"local\\\"), true)\\\
2830function handle.formatTime(nTime, bTwentyFourHour)\\\
2831 expect(1, nTime, \\\"number\\\")\\\
2832 expect(2, bTwentyFourHour, \\\"boolean\\\", \\\"nil\\\")\\\
2833 local sTOD = nil\\\
2834 if not bTwentyFourHour then\\\
2835 if nTime >= 12 then\\\
2836 sTOD = \\\"PM\\\"\\\
2837 else\\\
2838 sTOD = \\\"AM\\\"\\\
2839 end\\\
2840 if nTime >= 13 then\\\
2841 nTime = nTime - 12\\\
2842 end\\\
2843 end\\\
2844\\\
2845 local nHour = math.floor(nTime)\\\
2846 local nMinute = math.floor((nTime - nHour) * 60)\\\
2847 if sTOD then\\\
2848 return string.format(\\\"%d:%02d %s\\\", nHour == 0 and 12 or nHour, nMinute, sTOD)\\\
2849 else\\\
2850 return string.format(\\\"%d:%02d\\\", nHour, nMinute)\\\
2851 end\\\
2852end\\\
2853\\\
2854local function tabulateCommon(bPaged, ...)\\\
2855 local tAll = table.pack(...)\\\
2856 for i = 1, tAll.n do\\\
2857 expect(i, tAll[i], \\\"number\\\", \\\"table\\\")\\\
2858 end\\\
2859\\\
2860 local w, h = term.getSize()\\\
2861 local nMaxLen = w / 8\\\
2862 for n, t in ipairs(tAll) do\\\
2863 if type(t) == \\\"table\\\" then\\\
2864 for nu, sItem in pairs(t) do\\\
2865 local ty = type(sItem)\\\
2866 if ty ~= \\\"string\\\" and ty ~= \\\"number\\\" then\\\
2867 error(\\\"bad argument #\\\" .. n .. \\\".\\\" .. nu .. \\\" (expected string, got \\\" .. ty .. \\\")\\\", 3)\\\
2868 end\\\
2869 nMaxLen = math.max(#tostring(sItem) + 1, nMaxLen)\\\
2870 end\\\
2871 end\\\
2872 end\\\
2873 local nCols = math.floor(w / nMaxLen)\\\
2874 local nLines = 0\\\
2875 local function newLine()\\\
2876 if bPaged and nLines >= h - 3 then\\\
2877 handle.pagedPrint()\\\
2878 else\\\
2879 output.print()\\\
2880 end\\\
2881 nLines = nLines + 1\\\
2882 end\\\
2883\\\
2884 local function drawCols(_t)\\\
2885 local nCol = 1\\\
2886 for _, s in ipairs(_t) do\\\
2887 if nCol > nCols then\\\
2888 nCol = 1\\\
2889 newLine()\\\
2890 end\\\
2891\\\
2892 local cx, cy = term.getCursorPos()\\\
2893 cx = 1 + (nCol - 1) * nMaxLen\\\
2894 term.setCursorPos(cx, cy)\\\
2895 term.write(s)\\\
2896\\\
2897 nCol = nCol + 1\\\
2898 end\\\
2899 print()\\\
2900 end\\\
2901\\\
2902 local previous_colour = term.getTextColour()\\\
2903 for _, t in ipairs(tAll) do\\\
2904 if type(t) == \\\"table\\\" then\\\
2905 if #t > 0 then\\\
2906 drawCols(t)\\\
2907 end\\\
2908 elseif type(t) == \\\"number\\\" then\\\
2909 term.setTextColor(t)\\\
2910 end\\\
2911 end\\\
2912 term.setTextColor(previous_colour)\\\
2913end\\\
2914\\\
2915--[[- Prints tables in a structured form.\\\
2916\\\
2917This accepts multiple arguments, either a table or a number. When\\\
2918encountering a table, this will be treated as a table row, with each column\\\
2919width being auto-adjusted.\\\
2920\\\
2921When encountering a number, this sets the text color of the subsequent rows to it.\\\
2922\\\
2923@tparam {string...}|number ... The rows and text colors to display.\\\
2924@since 1.3\\\
2925@usage\\\
2926\\\
2927 textutils.tabulate(\\\
2928 colors.orange, { \\\"1\\\", \\\"2\\\", \\\"3\\\" },\\\
2929 colors.lightBlue, { \\\"A\\\", \\\"B\\\", \\\"C\\\" }\\\
2930 )\\\
2931]]\\\
2932function handle.tabulate(...)\\\
2933 return tabulateCommon(false, ...)\\\
2934end\\\
2935\\\
2936--[[- Prints tables in a structured form, stopping and prompting for input should\\\
2937the result not fit on the terminal.\\\
2938\\\
2939This functions identically to @{textutils.tabulate}, but will prompt for user\\\
2940input should the whole output not fit on the display.\\\
2941\\\
2942@tparam {string...}|number ... The rows and text colors to display.\\\
2943@see textutils.tabulate\\\
2944@see textutils.pagedPrint\\\
2945@since 1.3\\\
2946\\\
2947@usage Generates a long table, tabulates it, and prints it to the screen.\\\
2948\\\
2949 local rows = {}\\\
2950 for i = 1, 30 do rows[i] = {(\\\"Row #%d\\\"):format(i), math.random(1, 400)} end\\\
2951\\\
2952 textutils.pagedTabulate(colors.orange, {\\\"Column\\\", \\\"Value\\\"}, colors.lightBlue, table.unpack(rows))\\\
2953]]\\\
2954function handle.pagedTabulate(...)\\\
2955 return tabulateCommon(true, ...)\\\
2956end\\\
2957\\\
2958local g_tLuaKeywords = {\\\
2959 [\\\"and\\\"] = true,\\\
2960 [\\\"break\\\"] = true,\\\
2961 [\\\"do\\\"] = true,\\\
2962 [\\\"else\\\"] = true,\\\
2963 [\\\"elseif\\\"] = true,\\\
2964 [\\\"end\\\"] = true,\\\
2965 [\\\"false\\\"] = true,\\\
2966 [\\\"for\\\"] = true,\\\
2967 [\\\"function\\\"] = true,\\\
2968 [\\\"if\\\"] = true,\\\
2969 [\\\"in\\\"] = true,\\\
2970 [\\\"local\\\"] = true,\\\
2971 [\\\"nil\\\"] = true,\\\
2972 [\\\"not\\\"] = true,\\\
2973 [\\\"or\\\"] = true,\\\
2974 [\\\"repeat\\\"] = true,\\\
2975 [\\\"return\\\"] = true,\\\
2976 [\\\"then\\\"] = true,\\\
2977 [\\\"true\\\"] = true,\\\
2978 [\\\"until\\\"] = true,\\\
2979 [\\\"while\\\"] = true,\\\
2980}\\\
2981\\\
2982local serialize_infinity = math.huge\\\
2983local function serialize_impl(t, tracking, indent, opts)\\\
2984 local sType = type(t)\\\
2985 if sType == \\\"table\\\" then\\\
2986 if tracking[t] ~= nil then\\\
2987 if tracking[t] == false then\\\
2988 error(\\\"Cannot serialize table with repeated entries\\\", 0)\\\
2989 else\\\
2990 error(\\\"Cannot serialize table with recursive entries\\\", 0)\\\
2991 end\\\
2992 end\\\
2993 tracking[t] = true\\\
2994\\\
2995 local result\\\
2996 if next(t) == nil then\\\
2997 -- Empty tables are simple\\\
2998 result = \\\"{}\\\"\\\
2999 else\\\
3000 -- Other tables take more work\\\
3001 local open, sub_indent, open_key, close_key, equal, comma = \\\"{\\\\n\\\", indent .. \\\" \\\", \\\"[ \\\", \\\" ] = \\\", \\\" = \\\", \\\",\\\\n\\\"\\\
3002 if opts.compact then\\\
3003 open, sub_indent, open_key, close_key, equal, comma = \\\"{\\\", \\\"\\\", \\\"[\\\", \\\"]=\\\", \\\"=\\\", \\\",\\\"\\\
3004 end\\\
3005\\\
3006 result = open\\\
3007 local seen_keys = {}\\\
3008 for k, v in ipairs(t) do\\\
3009 seen_keys[k] = true\\\
3010 result = result .. sub_indent .. serialize_impl(v, tracking, sub_indent, opts) .. comma\\\
3011 end\\\
3012 for k, v in pairs(t) do\\\
3013 if not seen_keys[k] then\\\
3014 local sEntry\\\
3015 if type(k) == \\\"string\\\" and not g_tLuaKeywords[k] and string.match(k, \\\"^[%a_][%a%d_]*$\\\") then\\\
3016 sEntry = k .. equal .. serialize_impl(v, tracking, sub_indent, opts) .. comma\\\
3017 else\\\
3018 sEntry = open_key .. serialize_impl(k, tracking, sub_indent, opts) .. close_key .. serialize_impl(v, tracking, sub_indent, opts) .. comma\\\
3019 end\\\
3020 result = result .. sub_indent .. sEntry\\\
3021 end\\\
3022 end\\\
3023 result = result .. indent .. \\\"}\\\"\\\
3024 end\\\
3025\\\
3026 if opts.allow_repetitions then\\\
3027 tracking[t] = nil\\\
3028 else\\\
3029 tracking[t] = false\\\
3030 end\\\
3031 return result\\\
3032\\\
3033 elseif sType == \\\"string\\\" then\\\
3034 return string.format(\\\"%q\\\", t)\\\
3035\\\
3036 elseif sType == \\\"number\\\" then\\\
3037 if t ~= t then --nan\\\
3038 return \\\"0/0\\\"\\\
3039 elseif t == serialize_infinity then\\\
3040 return \\\"1/0\\\"\\\
3041 elseif t == -serialize_infinity then\\\
3042 return \\\"-1/0\\\"\\\
3043 else\\\
3044 return tostring(t)\\\
3045 end\\\
3046\\\
3047 elseif sType == \\\"boolean\\\" or sType == \\\"nil\\\" then\\\
3048 return tostring(t)\\\
3049\\\
3050 else\\\
3051 error(\\\"Cannot serialize type \\\" .. sType, 0)\\\
3052\\\
3053 end\\\
3054end\\\
3055\\\
3056local function mk_tbl(str, name)\\\
3057 local msg = \\\"attempt to mutate textutils.\\\" .. name\\\
3058 return setmetatable({}, {\\\
3059 __newindex = function() error(msg, 2) end,\\\
3060 __tostring = function() return str end,\\\
3061 })\\\
3062end\\\
3063\\\
3064--- A table representing an empty JSON array, in order to distinguish it from an\\\
3065-- empty JSON object.\\\
3066--\\\
3067-- The contents of this table should not be modified.\\\
3068--\\\
3069-- @usage textutils.serialiseJSON(textutils.empty_json_array)\\\
3070-- @see textutils.serialiseJSON\\\
3071-- @see textutils.unserialiseJSON\\\
3072handle.empty_json_array = mk_tbl(\\\"[]\\\", \\\"empty_json_array\\\")\\\
3073\\\
3074--- A table representing the JSON null value.\\\
3075--\\\
3076-- The contents of this table should not be modified.\\\
3077--\\\
3078-- @usage textutils.serialiseJSON(textutils.json_null)\\\
3079-- @see textutils.serialiseJSON\\\
3080-- @see textutils.unserialiseJSON\\\
3081handle.json_null = mk_tbl(\\\"null\\\", \\\"json_null\\\")\\\
3082\\\
3083local serializeJSONString\\\
3084do\\\
3085 local function hexify(c)\\\
3086 return (\\\"\\\\\\\\u00%02X\\\"):format(c:byte())\\\
3087 end\\\
3088\\\
3089 local map = {\\\
3090 [\\\"\\\\\\\"\\\"] = \\\"\\\\\\\\\\\\\\\"\\\",\\\
3091 [\\\"\\\\\\\\\\\"] = \\\"\\\\\\\\\\\\\\\\\\\",\\\
3092 [\\\"\\\\b\\\"] = \\\"\\\\\\\\b\\\",\\\
3093 [\\\"\\\\f\\\"] = \\\"\\\\\\\\f\\\",\\\
3094 [\\\"\\\\n\\\"] = \\\"\\\\\\\\n\\\",\\\
3095 [\\\"\\\\r\\\"] = \\\"\\\\\\\\r\\\",\\\
3096 [\\\"\\\\t\\\"] = \\\"\\\\\\\\t\\\",\\\
3097 }\\\
3098 for i = 0, 0x1f do\\\
3099 local c = string.char(i)\\\
3100 if map[c] == nil then map[c] = hexify(c) end\\\
3101 end\\\
3102\\\
3103 serializeJSONString = function(s)\\\
3104 return ('\\\"%s\\\"'):format(s:gsub(\\\"[%z\\\\1-\\\\x1f\\\\\\\"\\\\\\\\]\\\", map):gsub(\\\"[\\\\x7f-\\\\xff]\\\", hexify))\\\
3105 end\\\
3106end\\\
3107\\\
3108local function serializeJSONImpl(t, tTracking, bNBTStyle)\\\
3109 local sType = type(t)\\\
3110 if t == handle.empty_json_array then return \\\"[]\\\"\\\
3111 elseif t == handle.json_null then return \\\"null\\\"\\\
3112\\\
3113 elseif sType == \\\"table\\\" then\\\
3114 if tTracking[t] ~= nil then\\\
3115 error(\\\"Cannot serialize table with recursive entries\\\", 0)\\\
3116 end\\\
3117 tTracking[t] = true\\\
3118\\\
3119 if next(t) == nil then\\\
3120 -- Empty tables are simple\\\
3121 return \\\"{}\\\"\\\
3122 else\\\
3123 -- Other tables take more work\\\
3124 local sObjectResult = \\\"{\\\"\\\
3125 local sArrayResult = \\\"[\\\"\\\
3126 local nObjectSize = 0\\\
3127 local nArraySize = 0\\\
3128 local largestArrayIndex = 0\\\
3129 for k, v in pairs(t) do\\\
3130 if type(k) == \\\"string\\\" then\\\
3131 local sEntry\\\
3132 if bNBTStyle then\\\
3133 sEntry = tostring(k) .. \\\":\\\" .. serializeJSONImpl(v, tTracking, bNBTStyle)\\\
3134 else\\\
3135 sEntry = serializeJSONString(k) .. \\\":\\\" .. serializeJSONImpl(v, tTracking, bNBTStyle)\\\
3136 end\\\
3137 if nObjectSize == 0 then\\\
3138 sObjectResult = sObjectResult .. sEntry\\\
3139 else\\\
3140 sObjectResult = sObjectResult .. \\\",\\\" .. sEntry\\\
3141 end\\\
3142 nObjectSize = nObjectSize + 1\\\
3143 elseif type(k) == \\\"number\\\" and k > largestArrayIndex then --the largest index is kept to avoid losing half the array if there is any single nil in that array\\\
3144 largestArrayIndex = k\\\
3145 end\\\
3146 end\\\
3147 for k = 1, largestArrayIndex, 1 do --the array is read up to the very last valid array index, ipairs() would stop at the first nil value and we would lose any data after.\\\
3148 local sEntry\\\
3149 if t[k] == nil then --if the array is nil at index k the value is \\\"null\\\" as to keep the unused indexes in between used ones.\\\
3150 sEntry = \\\"null\\\"\\\
3151 else -- if the array index does not point to a nil we serialise it's content.\\\
3152 sEntry = serializeJSONImpl(t[k], tTracking, bNBTStyle)\\\
3153 end\\\
3154 if nArraySize == 0 then\\\
3155 sArrayResult = sArrayResult .. sEntry\\\
3156 else\\\
3157 sArrayResult = sArrayResult .. \\\",\\\" .. sEntry\\\
3158 end\\\
3159 nArraySize = nArraySize + 1\\\
3160 end\\\
3161 sObjectResult = sObjectResult .. \\\"}\\\"\\\
3162 sArrayResult = sArrayResult .. \\\"]\\\"\\\
3163 if nObjectSize > 0 or nArraySize == 0 then\\\
3164 return sObjectResult\\\
3165 else\\\
3166 return sArrayResult\\\
3167 end\\\
3168 end\\\
3169\\\
3170 elseif sType == \\\"string\\\" then\\\
3171 return serializeJSONString(t)\\\
3172\\\
3173 elseif sType == \\\"number\\\" or sType == \\\"boolean\\\" then\\\
3174 return tostring(t)\\\
3175\\\
3176 else\\\
3177 error(\\\"Cannot serialize type \\\" .. sType, 0)\\\
3178\\\
3179 end\\\
3180end\\\
3181\\\
3182local unserialise_json\\\
3183do\\\
3184 local sub, find, match, concat, tonumber = string.sub, string.find, string.match, table.concat, tonumber\\\
3185\\\
3186 --- Skip any whitespace\\\
3187 local function skip(str, pos)\\\
3188 local _, last = find(str, \\\"^[ \\\\n\\\\r\\\\t]+\\\", pos)\\\
3189 if last then return last + 1 else return pos end\\\
3190 end\\\
3191\\\
3192 local escapes = {\\\
3193 [\\\"b\\\"] = '\\\\b', [\\\"f\\\"] = '\\\\f', [\\\"n\\\"] = '\\\\n', [\\\"r\\\"] = '\\\\r', [\\\"t\\\"] = '\\\\t',\\\
3194 [\\\"\\\\\\\"\\\"] = \\\"\\\\\\\"\\\", [\\\"/\\\"] = \\\"/\\\", [\\\"\\\\\\\\\\\"] = \\\"\\\\\\\\\\\",\\\
3195 }\\\
3196\\\
3197 local mt = {}\\\
3198\\\
3199 local function error_at(pos, msg, ...)\\\
3200 if select('#', ...) > 0 then msg = msg:format(...) end\\\
3201 error(setmetatable({ pos = pos, msg = msg }, mt))\\\
3202 end\\\
3203\\\
3204 local function expected(pos, actual, exp)\\\
3205 if actual == \\\"\\\" then actual = \\\"end of input\\\" else actual = (\\\"%q\\\"):format(actual) end\\\
3206 error_at(pos, \\\"Unexpected %s, expected %s.\\\", actual, exp)\\\
3207 end\\\
3208\\\
3209 local function parse_string(str, pos, terminate)\\\
3210 local buf, n = {}, 1\\\
3211\\\
3212 while true do\\\
3213 local c = sub(str, pos, pos)\\\
3214 if c == \\\"\\\" then error_at(pos, \\\"Unexpected end of input, expected '\\\\\\\"'.\\\") end\\\
3215 if c == terminate then break end\\\
3216\\\
3217 if c == '\\\\\\\\' then\\\
3218 -- Handle the various escapes\\\
3219 c = sub(str, pos + 1, pos + 1)\\\
3220 if c == \\\"\\\" then error_at(pos, \\\"Unexpected end of input, expected escape sequence.\\\") end\\\
3221\\\
3222 if c == \\\"u\\\" then\\\
3223 local num_str = match(str, \\\"^%x%x%x%x\\\", pos + 2)\\\
3224 if not num_str then error_at(pos, \\\"Malformed unicode escape %q.\\\", sub(str, pos + 2, pos + 5)) end\\\
3225 buf[n], n, pos = utf8.char(tonumber(num_str, 16)), n + 1, pos + 6\\\
3226 else\\\
3227 local unesc = escapes[c]\\\
3228 if not unesc then error_at(pos + 1, \\\"Unknown escape character %q.\\\", c) end\\\
3229 buf[n], n, pos = unesc, n + 1, pos + 2\\\
3230 end\\\
3231 elseif c >= '\\\\x20' then\\\
3232 buf[n], n, pos = c, n + 1, pos + 1\\\
3233 else\\\
3234 error_at(pos + 1, \\\"Unescaped whitespace %q.\\\", c)\\\
3235 end\\\
3236 end\\\
3237\\\
3238 return concat(buf, \\\"\\\", 1, n - 1), pos + 1\\\
3239 end\\\
3240\\\
3241 local num_types = { b = true, B = true, s = true, S = true, l = true, L = true, f = true, F = true, d = true, D = true }\\\
3242 local function parse_number(str, pos, opts)\\\
3243 local _, last, num_str = find(str, '^(-?%d+%.?%d*[eE]?[+-]?%d*)', pos)\\\
3244 local val = tonumber(num_str)\\\
3245 if not val then error_at(pos, \\\"Malformed number %q.\\\", num_str) end\\\
3246\\\
3247 if opts.nbt_style and num_types[sub(str, last + 1, last + 1)] then return val, last + 2 end\\\
3248\\\
3249 return val, last + 1\\\
3250 end\\\
3251\\\
3252 local function parse_ident(str, pos)\\\
3253 local _, last, val = find(str, '^([%a][%w_]*)', pos)\\\
3254 return val, last + 1\\\
3255 end\\\
3256\\\
3257 local arr_types = { I = true, L = true, B = true }\\\
3258 local function decode_impl(str, pos, opts)\\\
3259 local c = sub(str, pos, pos)\\\
3260 if c == '\\\"' then return parse_string(str, pos + 1, '\\\"')\\\
3261 elseif c == \\\"'\\\" and opts.nbt_style then return parse_string(str, pos + 1, \\\"\\\\'\\\")\\\
3262 elseif c == \\\"-\\\" or c >= \\\"0\\\" and c <= \\\"9\\\" then return parse_number(str, pos, opts)\\\
3263 elseif c == \\\"t\\\" then\\\
3264 if sub(str, pos + 1, pos + 3) == \\\"rue\\\" then return true, pos + 4 end\\\
3265 elseif c == 'f' then\\\
3266 if sub(str, pos + 1, pos + 4) == \\\"alse\\\" then return false, pos + 5 end\\\
3267 elseif c == 'n' then\\\
3268 if sub(str, pos + 1, pos + 3) == \\\"ull\\\" then\\\
3269 if opts.parse_null then\\\
3270 return handle.json_null, pos + 4\\\
3271 else\\\
3272 return nil, pos + 4\\\
3273 end\\\
3274 end\\\
3275 elseif c == \\\"{\\\" then\\\
3276 local obj = {}\\\
3277\\\
3278 pos = skip(str, pos + 1)\\\
3279 c = sub(str, pos, pos)\\\
3280\\\
3281 if c == \\\"\\\" then return error_at(pos, \\\"Unexpected end of input, expected '}'.\\\") end\\\
3282 if c == \\\"}\\\" then return obj, pos + 1 end\\\
3283\\\
3284 while true do\\\
3285 local key, value\\\
3286 if c == \\\"\\\\\\\"\\\" then key, pos = parse_string(str, pos + 1, \\\"\\\\\\\"\\\")\\\
3287 elseif opts.nbt_style then key, pos = parse_ident(str, pos)\\\
3288 else return expected(pos, c, \\\"object key\\\")\\\
3289 end\\\
3290\\\
3291 pos = skip(str, pos)\\\
3292\\\
3293 c = sub(str, pos, pos)\\\
3294 if c ~= \\\":\\\" then return expected(pos, c, \\\"':'\\\") end\\\
3295\\\
3296 value, pos = decode_impl(str, skip(str, pos + 1), opts)\\\
3297 obj[key] = value\\\
3298\\\
3299 -- Consume the next delimiter\\\
3300 pos = skip(str, pos)\\\
3301 c = sub(str, pos, pos)\\\
3302 if c == \\\"}\\\" then break\\\
3303 elseif c == \\\",\\\" then pos = skip(str, pos + 1)\\\
3304 else return expected(pos, c, \\\"',' or '}'\\\")\\\
3305 end\\\
3306\\\
3307 c = sub(str, pos, pos)\\\
3308 end\\\
3309\\\
3310 return obj, pos + 1\\\
3311\\\
3312 elseif c == \\\"[\\\" then\\\
3313 local arr, n = {}, 1\\\
3314\\\
3315 pos = skip(str, pos + 1)\\\
3316 c = sub(str, pos, pos)\\\
3317\\\
3318 if arr_types[c] and sub(str, pos + 1, pos + 1) == \\\";\\\" and opts.nbt_style then\\\
3319 pos = skip(str, pos + 2)\\\
3320 c = sub(str, pos, pos)\\\
3321 end\\\
3322\\\
3323 if c == \\\"\\\" then return expected(pos, c, \\\"']'\\\") end\\\
3324 if c == \\\"]\\\" then\\\
3325 if opts.parse_empty_array ~= false then\\\
3326 return handle.empty_json_array, pos + 1\\\
3327 else\\\
3328 return {}, pos + 1\\\
3329 end\\\
3330 end\\\
3331\\\
3332 while true do\\\
3333 n, arr[n], pos = n + 1, decode_impl(str, pos, opts)\\\
3334\\\
3335 -- Consume the next delimiter\\\
3336 pos = skip(str, pos)\\\
3337 c = sub(str, pos, pos)\\\
3338 if c == \\\"]\\\" then break\\\
3339 elseif c == \\\",\\\" then pos = skip(str, pos + 1)\\\
3340 else return expected(pos, c, \\\"',' or ']'\\\")\\\
3341 end\\\
3342 end\\\
3343\\\
3344 return arr, pos + 1\\\
3345 elseif c == \\\"\\\" then error_at(pos, 'Unexpected end of input.')\\\
3346 end\\\
3347\\\
3348 error_at(pos, \\\"Unexpected character %q.\\\", c)\\\
3349 end\\\
3350\\\
3351 --[[- Converts a serialised JSON string back into a reassembled Lua object.\\\
3352\\\
3353 This may be used with @{textutils.serializeJSON}, or when communicating\\\
3354 with command blocks or web APIs.\\\
3355\\\
3356 If a `null` value is encountered, it is converted into `nil`. It can be converted\\\
3357 into @{textutils.json_null} with the `parse_null` option.\\\
3358\\\
3359 If an empty array is encountered, it is converted into @{textutils.empty_json_array}.\\\
3360 It can be converted into a new empty table with the `parse_empty_array` option.\\\
3361\\\
3362 @tparam string s The serialised string to deserialise.\\\
3363 @tparam[opt] { nbt_style? = boolean, parse_null? = boolean, parse_empty_array? = boolean } options\\\
3364 Options which control how this JSON object is parsed.\\\
3365\\\
3366 - `nbt_style`: When true, this will accept [stringified NBT][nbt] strings,\\\
3367 as produced by many commands.\\\
3368 - `parse_null`: When true, `null` will be parsed as @{json_null}, rather than\\\
3369 `nil`.\\\
3370 - `parse_empty_array`: When false, empty arrays will be parsed as a new table.\\\
3371 By default (or when this value is true), they are parsed as @{empty_json_array}.\\\
3372\\\
3373 [nbt]: https://minecraft.gamepedia.com/NBT_format\\\
3374 @return[1] The deserialised object\\\
3375 @treturn[2] nil If the object could not be deserialised.\\\
3376 @treturn string A message describing why the JSON string is invalid.\\\
3377 @since 1.87.0\\\
3378 @changed 1.100.6 Added `parse_empty_array` option\\\
3379 @see textutils.json_null Use to serialize a JSON `null` value.\\\
3380 @see textutils.empty_json_array Use to serialize a JSON empty array.\\\
3381 @usage Unserialise a basic JSON object\\\
3382\\\
3383 textutils.unserialiseJSON('{\\\"name\\\": \\\"Steve\\\", \\\"age\\\": null}')\\\
3384\\\
3385 @usage Unserialise a basic JSON object, returning null values as @{json_null}.\\\
3386\\\
3387 textutils.unserialiseJSON('{\\\"name\\\": \\\"Steve\\\", \\\"age\\\": null}', { parse_null = true })\\\
3388 ]]\\\
3389 unserialise_json = function(s, options)\\\
3390 expect(1, s, \\\"string\\\")\\\
3391 expect(2, options, \\\"table\\\", \\\"nil\\\")\\\
3392\\\
3393 if options then\\\
3394 field(options, \\\"nbt_style\\\", \\\"boolean\\\", \\\"nil\\\")\\\
3395 field(options, \\\"parse_null\\\", \\\"boolean\\\", \\\"nil\\\")\\\
3396 field(options, \\\"parse_empty_array\\\", \\\"boolean\\\", \\\"nil\\\")\\\
3397 else\\\
3398 options = {}\\\
3399 end\\\
3400\\\
3401 local ok, res, pos = pcall(decode_impl, s, skip(s, 1), options)\\\
3402 if not ok then\\\
3403 if type(res) == \\\"table\\\" and getmetatable(res) == mt then\\\
3404 return nil, (\\\"Malformed JSON at position %d: %s\\\"):format(res.pos, res.msg)\\\
3405 end\\\
3406\\\
3407 error(res, 0)\\\
3408 end\\\
3409\\\
3410 pos = skip(s, pos)\\\
3411 if pos <= #s then\\\
3412 return nil, (\\\"Malformed JSON at position %d: Unexpected trailing character %q.\\\"):format(pos, sub(s, pos, pos))\\\
3413 end\\\
3414 return res\\\
3415\\\
3416 end\\\
3417end\\\
3418handle.unserialise_json = unserialise_json\\\
3419--[[- Convert a Lua object into a textual representation, suitable for\\\
3420saving in a file or pretty-printing.\\\
3421\\\
3422@param t The object to serialise\\\
3423@tparam { compact? = boolean, allow_repetitions? = boolean } opts Options for serialisation.\\\
3424 - `compact`: Do not emit indentation and other whitespace between terms.\\\
3425 - `allow_repetitions`: Relax the check for recursive tables, allowing them to appear multiple\\\
3426 times (as long as tables do not appear inside themselves).\\\
3427\\\
3428@treturn string The serialised representation\\\
3429@throws If the object contains a value which cannot be\\\
3430serialised. This includes functions and tables which appear multiple\\\
3431times.\\\
3432@see cc.pretty.pretty_print An alternative way to display a table, often more\\\
3433suitable for pretty printing.\\\
3434@since 1.3\\\
3435@changed 1.97.0 Added `opts` argument.\\\
3436@usage Serialise a basic table.\\\
3437\\\
3438 textutils.serialise({ 1, 2, 3, a = 1, [\\\"another key\\\"] = { true } })\\\
3439\\\
3440@usage Demonstrates some of the other options\\\
3441\\\
3442 local tbl = { 1, 2, 3 }\\\
3443 print(textutils.serialise({ tbl, tbl }, { allow_repetitions = true }))\\\
3444\\\
3445 print(textutils.serialise(tbl, { compact = true }))\\\
3446]]\\\
3447function handle.serialize(t, opts)\\\
3448 local tTracking = {}\\\
3449 expect(2, opts, \\\"table\\\", \\\"nil\\\")\\\
3450\\\
3451 if opts then\\\
3452 field(opts, \\\"compact\\\", \\\"boolean\\\", \\\"nil\\\")\\\
3453 field(opts, \\\"allow_repetitions\\\", \\\"boolean\\\", \\\"nil\\\")\\\
3454 else\\\
3455 opts = {}\\\
3456 end\\\
3457 return serialize_impl(t, tTracking, \\\"\\\", opts)\\\
3458end\\\
3459\\\
3460--- Converts a serialised string back into a reassembled Lua object.\\\
3461--\\\
3462-- This is mainly used together with @{textutils.serialise}.\\\
3463--\\\
3464-- @tparam string s The serialised string to deserialise.\\\
3465-- @return[1] The deserialised object\\\
3466-- @treturn[2] nil If the object could not be deserialised.\\\
3467-- @since 1.3\\\
3468function handle.unserialize(s)\\\
3469 expect(1, s, \\\"string\\\")\\\
3470 local func = os.load(\\\"return \\\" .. s, \\\"unserialize\\\", \\\"t\\\", {})\\\
3471 if func then\\\
3472 local ok, result = pcall(func)\\\
3473 if ok then\\\
3474 return result\\\
3475 end\\\
3476 end\\\
3477 return nil\\\
3478end\\\
3479--- Returns a JSON representation of the given data.\\\
3480--\\\
3481-- This function attempts to guess whether a table is a JSON array or\\\
3482-- object. However, empty tables are assumed to be empty objects - use\\\
3483-- @{textutils.empty_json_array} to mark an empty array.\\\
3484--\\\
3485-- This is largely intended for interacting with various functions from the\\\
3486-- @{commands} API, though may also be used in making @{http} requests.\\\
3487--\\\
3488-- @param t The value to serialise. Like @{textutils.serialise}, this should not\\\
3489-- contain recursive tables or functions.\\\
3490-- @tparam[opt] boolean bNBTStyle Whether to produce NBT-style JSON (non-quoted keys)\\\
3491-- instead of standard JSON.\\\
3492-- @treturn string The JSON representation of the input.\\\
3493-- @throws If the object contains a value which cannot be\\\
3494-- serialised. This includes functions and tables which appear multiple\\\
3495-- times.\\\
3496-- @usage textutils.serialiseJSON({ values = { 1, \\\"2\\\", true } })\\\
3497-- @since 1.7\\\
3498-- @see textutils.json_null Use to serialise a JSON `null` value.\\\
3499-- @see textutils.empty_json_array Use to serialise a JSON empty array.\\\
3500function handle.serializeJSON(t, bNBTStyle)\\\
3501 expect(1, t, \\\"table\\\", \\\"string\\\", \\\"number\\\", \\\"boolean\\\")\\\
3502 expect(2, bNBTStyle, \\\"boolean\\\", \\\"nil\\\")\\\
3503 local tTracking = {}\\\
3504 return serializeJSONImpl(t, tTracking, bNBTStyle or false)\\\
3505end\\\
3506\\\
3507--- Replaces certain characters in a string to make it safe for use in URLs or POST data.\\\
3508--\\\
3509-- @tparam string str The string to encode\\\
3510-- @treturn string The encoded string.\\\
3511-- @usage print(\\\"https://example.com/?view=\\\" .. textutils.urlEncode(\\\"some text&things\\\"))\\\
3512-- @since 1.31\\\
3513function handle.urlEncode(str)\\\
3514 expect(1, str, \\\"string\\\")\\\
3515 if str then\\\
3516 str = string.gsub(str, \\\"\\\\n\\\", \\\"\\\\r\\\\n\\\")\\\
3517 str = string.gsub(str, \\\"([^A-Za-z0-9 %-%_%.])\\\", function(c)\\\
3518 local n = string.byte(c)\\\
3519 if n < 128 then\\\
3520 -- ASCII\\\
3521 return string.format(\\\"%%%02X\\\", n)\\\
3522 else\\\
3523 -- Non-ASCII (encode as UTF-8)\\\
3524 return\\\
3525 string.format(\\\"%%%02X\\\", 192 + bit32.band(bit32.arshift(n, 6), 31)) ..\\\
3526 string.format(\\\"%%%02X\\\", 128 + bit32.band(n, 63))\\\
3527 end\\\
3528 end)\\\
3529 str = string.gsub(str, \\\" \\\", \\\"+\\\")\\\
3530 end\\\
3531 return str\\\
3532end\\\
3533\\\
3534local tEmpty = {}\\\
3535\\\
3536--- Provides a list of possible completions for a partial Lua expression.\\\
3537--\\\
3538-- If the completed element is a table, suggestions will have `.` appended to\\\
3539-- them. Similarly, functions have `(` appended to them.\\\
3540--\\\
3541-- @tparam string sSearchText The partial expression to complete, such as a\\\
3542-- variable name or table index.\\\
3543--\\\
3544-- @tparam[opt] table tSearchTable The table to find variables in, defaulting to\\\
3545-- the global environment (@{_G}). The function also searches the \\\"parent\\\"\\\
3546-- environment via the `__index` metatable field.\\\
3547--\\\
3548-- @treturn { string... } The (possibly empty) list of completions.\\\
3549-- @see shell.setCompletionFunction\\\
3550-- @see _G.read\\\
3551-- @usage textutils.complete( \\\"pa\\\", _ENV )\\\
3552-- @since 1.74\\\
3553function handle.complete(sSearchText, tSearchTable)\\\
3554 expect(1, sSearchText, \\\"string\\\")\\\
3555 expect(2, tSearchTable, \\\"table\\\", \\\"nil\\\")\\\
3556\\\
3557 if g_tLuaKeywords[sSearchText] then return tEmpty end\\\
3558 local nStart = 1\\\
3559 local nDot = string.find(sSearchText, \\\".\\\", nStart, true)\\\
3560 local tTable = tSearchTable or _ENV\\\
3561 while nDot do\\\
3562 local sPart = string.sub(sSearchText, nStart, nDot - 1)\\\
3563 local value = tTable[sPart]\\\
3564 if type(value) == \\\"table\\\" then\\\
3565 tTable = value\\\
3566 nStart = nDot + 1\\\
3567 nDot = string.find(sSearchText, \\\".\\\", nStart, true)\\\
3568 else\\\
3569 return tEmpty\\\
3570 end\\\
3571 end\\\
3572 local nColon = string.find(sSearchText, \\\":\\\", nStart, true)\\\
3573 if nColon then\\\
3574 local sPart = string.sub(sSearchText, nStart, nColon - 1)\\\
3575 local value = tTable[sPart]\\\
3576 if type(value) == \\\"table\\\" then\\\
3577 tTable = value\\\
3578 nStart = nColon + 1\\\
3579 else\\\
3580 return tEmpty\\\
3581 end\\\
3582 end\\\
3583\\\
3584 local sPart = string.sub(sSearchText, nStart)\\\
3585 local nPartLength = #sPart\\\
3586\\\
3587 local tResults = {}\\\
3588 local tSeen = {}\\\
3589 while tTable do\\\
3590 for k, v in pairs(tTable) do\\\
3591 if not tSeen[k] and type(k) == \\\"string\\\" then\\\
3592 if string.find(k, sPart, 1, true) == 1 then\\\
3593 if not g_tLuaKeywords[k] and string.match(k, \\\"^[%a_][%a%d_]*$\\\") then\\\
3594 local sResult = string.sub(k, nPartLength + 1)\\\
3595 if nColon then\\\
3596 if type(v) == \\\"function\\\" then\\\
3597 table.insert(tResults, sResult .. \\\"(\\\")\\\
3598 elseif type(v) == \\\"table\\\" then\\\
3599 local tMetatable = getmetatable(v)\\\
3600 if tMetatable and (type(tMetatable.__call) == \\\"function\\\" or type(tMetatable.__call) == \\\"table\\\") then\\\
3601 table.insert(tResults, sResult .. \\\"(\\\")\\\
3602 end\\\
3603 end\\\
3604 else\\\
3605 if type(v) == \\\"function\\\" then\\\
3606 sResult = sResult .. \\\"(\\\"\\\
3607 elseif type(v) == \\\"table\\\" and next(v) ~= nil then\\\
3608 sResult = sResult .. \\\".\\\"\\\
3609 end\\\
3610 table.insert(tResults, sResult)\\\
3611 end\\\
3612 end\\\
3613 end\\\
3614 end\\\
3615 tSeen[k] = true\\\
3616 end\\\
3617 local tMetatable = getmetatable(tTable)\\\
3618 if tMetatable and type(tMetatable.__index) == \\\"table\\\" then\\\
3619 tTable = tMetatable.__index\\\
3620 else\\\
3621 tTable = nil\\\
3622 end\\\
3623 end\\\
3624\\\
3625 table.sort(tResults)\\\
3626 return tResults\\\
3627end\\\
3628return handle\",\
3629 Path = \"boot/modules/strings.lua\",\
3630 },\
3631 {\
3632 func = \"\\\
3633local expect = (require and require \\\"cc.expect\\\") or (os.dofile and os.dofile(\\\"rom/modules/main/cc/expect.lua\\\")) or nil\\\
3634if expect == nil\\\
3635then\\\
3636 local h = fs.open(\\\"rom/modules/main/cc/expect.lua\\\", \\\"r\\\")\\\
3637 local f, err = (_VERSION == \\\"Lua 5.1\\\" and loadstring or load)(h.readAll(), \\\"@expect.lua\\\",\\\"t\\\")\\\
3638 h.close()\\\
3639 if not f then error(err) end\\\
3640 expect = f().expect\\\
3641 end\\\
3642local fs,string,table = fs,string,table\\\
3643local setmetatable = setmetatable\\\
3644local getmetatable = getmetatable\\\
3645local utilties = {}\\\
3646utilties.string = {}\\\
3647utilties.table = {}\\\
3648utilties.file = {}\\\
3649-- strings addons \\\
3650function utilties.string.split(inputstr, sep)\\\
3651 if sep == nil then\\\
3652 sep = \\\"%s\\\"\\\
3653 end\\\
3654 local t={}\\\
3655 for str in string.gmatch(inputstr, \\\"([^\\\"..sep..\\\"]+)\\\") do\\\
3656 table.insert(t, str)\\\
3657 end\\\
3658 return t\\\
3659end\\\
3660-- fs addons\\\
3661function utilties.file.created(sPath)\\\
3662 expect(1,sPath,\\\"string\\\")\\\
3663 return fs.attributes(sPath).created\\\
3664end\\\
3665function utilties.file.modified(sPath)\\\
3666 expect(1,sPath,\\\"string\\\")\\\
3667 return fs.attributes(sPath).modified\\\
3668end\\\
3669\\\
3670function utilties.file.getExtension(file)\\\
3671 expect(1,file,\\\"string\\\")\\\
3672 local Table = utilties.string.split(file,\\\"%.\\\")\\\
3673 return Table[2]\\\
3674end\\\
3675function utilties.file.withoutExtension(file)\\\
3676 expect(1,file,\\\"string\\\")\\\
3677 local Table = utilties.string.split(file,\\\"%.\\\")\\\
3678 return Table[1]\\\
3679end\\\
3680function utilties.file.listsubs(sPath,showFiles,JustFiles,showRootDir,showRom)\\\
3681 expect(1,sPath,\\\"string\\\")\\\
3682 expect(2,showFiles,\\\"boolean\\\",\\\"nil\\\")\\\
3683 expect(4,JustFiles,\\\"boolean\\\",\\\"nil\\\")\\\
3684 expect(5,showRootDir,\\\"boolean\\\",\\\"nil\\\")\\\
3685 expect(6,showRom,\\\"boolean\\\",\\\"nil\\\")\\\
3686 if not fs.exists(sPath) then\\\
3687 error(\\\"Could not find\\\"..fs.getName(sPath))\\\
3688 end\\\
3689 if not fs.isDir(sPath) then\\\
3690 error(fs.getName(sPath)..\\\"is not a directory\\\")\\\
3691 end\\\
3692 local Table = fs.find(sPath..\\\"/*\\\")\\\
3693 if not showRom\\\
3694 then\\\
3695 local ID = utilties.table.find(Table,\\\"rom\\\")\\\
3696 if ID\\\
3697 then\\\
3698 table.remove(Table,ID)\\\
3699 end\\\
3700 end\\\
3701 local list = {}\\\
3702 if showRootDir and not JustFiles\\\
3703 then\\\
3704 table.insert(list,sPath)\\\
3705 end\\\
3706 for _,v in pairs(Table) do\\\
3707 if fs.isDir(v) then\\\
3708 if not JustFiles\\\
3709 then\\\
3710 table.insert(list,v)\\\
3711 end\\\
3712 local list2 = fs.find(fs.combine(v,\\\"*\\\"))\\\
3713 for _,b in pairs(list2) do\\\
3714 if fs.isDir(b)\\\
3715 then\\\
3716 table.insert(Table,b)\\\
3717 else\\\
3718 if showFiles or JustFiles\\\
3719 then\\\
3720 table.insert(list,b)\\\
3721 end\\\
3722 end\\\
3723 end\\\
3724 else\\\
3725 if showFiles or JustFiles\\\
3726 then\\\
3727 table.insert(list,v)\\\
3728 end\\\
3729 end\\\
3730 end\\\
3731 return list\\\
3732end\\\
3733function utilties.file.list(_sPath,showFiles,showPath,JustFiles,showDirs,justDirs)\\\
3734 expect(1,_sPath,\\\"string\\\")\\\
3735 expect(2,showFiles,\\\"boolean\\\",\\\"nil\\\")\\\
3736 expect(3,showPath,\\\"boolean\\\",\\\"nil\\\")\\\
3737 expect(5,JustFiles,\\\"boolean\\\",\\\"nil\\\")\\\
3738 expect(4,showDirs,\\\"boolean\\\",\\\"nil\\\")\\\
3739\\\
3740\\\
3741 if not fs.exists(_sPath)\\\
3742 then\\\
3743 error((\\\"%s : not found\\\"):format(_sPath),3)\\\
3744 end\\\
3745 if not fs.isDir(_sPath)\\\
3746 then\\\
3747 error((\\\"%s: is file expected directory\\\"):format(_sPath),3)\\\
3748 end\\\
3749 local list = fs.find(fs.combine(_sPath,\\\"*\\\"))\\\
3750 local list2 = {}\\\
3751 for _,v in pairs(list) do\\\
3752 if fs.isDir(v) and (not JustFiles) and (showDirs or justDirs)\\\
3753 then\\\
3754 table.insert(list2,v)\\\
3755 elseif not fs.isDir(v) and showFiles and not justDirs\\\
3756 then\\\
3757 table.insert(list2,v)\\\
3758 end\\\
3759 end\\\
3760 if not showPath\\\
3761 then\\\
3762 for i,v in pairs(list2) do\\\
3763 list2[i] = fs.getName(v)\\\
3764 end\\\
3765 end\\\
3766 return list2\\\
3767end\\\
3768function utilties.file.getDir(path)\\\
3769 expect(1,path,\\\"string\\\")\\\
3770 if fs.getDir(path) == \\\"..\\\"\\\
3771 then\\\
3772 return \\\"\\\"\\\
3773 else\\\
3774 return fs.getDir(path)\\\
3775 end\\\
3776end\\\
3777-- table addons\\\
3778function utilties.table.find(base,ID)\\\
3779 expect(1,base,\\\"table\\\")\\\
3780 for i,v in pairs(base) do\\\
3781 if type(ID) == \\\"string\\\" and type(v) == \\\"string\\\"\\\
3782 then\\\
3783 if string.find(v,ID)\\\
3784 then\\\
3785 return i\\\
3786 end\\\
3787 else\\\
3788 if ID == v\\\
3789 then\\\
3790 return i\\\
3791 end\\\
3792 end\\\
3793 end\\\
3794return false\\\
3795end\\\
3796function utilties.table.copy(Table,proxy)\\\
3797 expect(1,Table,\\\"table\\\")\\\
3798 expect(2,proxy,\\\"table\\\",\\\"nil\\\")\\\
3799 proxy = proxy or {}\\\
3800 local metatable = getmetatable(Table)\\\
3801 for k,v in pairs(Table) do\\\
3802 if type(v) == \\\"table\\\" and not utilties.table.find(v,v)\\\
3803 then\\\
3804 local Temp = utilties.table.copy(v)\\\
3805 proxy[k] = Temp\\\
3806 elseif type(v) ~= \\\"table\\\"\\\
3807 then\\\
3808 proxy[k] = v\\\
3809 end\\\
3810 end\\\
3811 return setmetatable(proxy,metatable)\\\
3812end\\\
3813return utilties\",\
3814 Path = \"boot/modules/utilties.lua\",\
3815 },\
3816 {\
3817 func = \"note: the bios uses the CC:tweaked APIS i am not claming ownership or credit but had to modfiey the code to make the bios work in the format i wanted\\\
3818-- main change\\\
3819got rid of the textutil API by moveing spliting it into a output and string module \\\
3820\",\
3821 Path = \"boot/notice.txt\",\
3822 },\
3823 {\
3824 func = \"-- UnBIOS by JackMacWindows\\\
3825-- This will undo most of the changes/additions made in the BIOS, but some things may remain wrapped if `debug` is unavailable\\\
3826-- To use, just place a `bios.lua` in the root of the drive, and run this program\\\
3827-- Here's a list of things that are irreversibly changed:\\\
3828-- * both `bit` and `bit32` are kept for compatibility\\\
3829-- * string metatable blocking (on old versions of CC)\\\
3830-- In addition, if `debug` is not available these things are also irreversibly changed:\\\
3831-- * old Lua 5.1 `load` function (for loading from a function)\\\
3832-- * `loadstring` prefixing (before CC:T 1.96.0)\\\
3833-- * `http.request`\\\
3834-- * `os.shutdown` and `os.reboot`\\\
3835-- * `peripheral`\\\
3836-- * `turtle.equip[Left|Right]`\\\
3837-- Licensed under the MIT license\\\
3838if _HOST:find(\\\"UnBIOS\\\") then return end\\\
3839local keptAPIs = {bit32 = true, bit = true, ccemux = true, config = true, coroutine = true, debug = true, fs = true, http = true, mounter = true, os = true, periphemu = true, peripheral = true, redstone = true, rs = true, term = true, utf8 = true, _HOST = true, _CC_DEFAULT_SETTINGS = true, _CC_DISABLE_LUA51_FEATURES = true, _VERSION = true, assert = true, collectgarbage = true, error = true, gcinfo = true, getfenv = true, getmetatable = true, ipairs = true, __inext = true,load = true, loadstring = true, math = true, newproxy = true, next = true, pairs = true, pcall = true, rawequal = true, rawget = true, rawlen = true, rawset = true, select = true, setfenv = true, setmetatable = true, string = true, table = true, tonumber = true, tostring = true, type = true, unpack = true, xpcall = true, turtle = true, pocket = true, commands = true, _G = true}\\\
3840local t = {}\\\
3841for k in pairs(_G) do if not keptAPIs[k] then table.insert(t, k) end end\\\
3842for _,k in ipairs(t) do _G[k] = nil end\\\
3843local native = _G.term.native()\\\
3844for _, method in ipairs {\\\"nativePaletteColor\\\", \\\"nativePaletteColour\\\", \\\"screenshot\\\"} do native[method] = _G.term[method] end\\\
3845_G.term = native\\\
3846_G.http.checkURL = _G.http.checkURLAsync\\\
3847_G.http.websocket = _G.http.websocketAsync\\\
3848if _G.commands then _G.commands = _G.commands.native end\\\
3849if _G.turtle then _G.turtle.native, _G.turtle.craft = nil end\\\
3850local delete = {os = {\\\"version\\\", \\\"pullEventRaw\\\", \\\"pullEvent\\\", \\\"run\\\", \\\"loadAPI\\\", \\\"unloadAPI\\\", \\\"sleep\\\"}, http = {\\\"get\\\", \\\"post\\\", \\\"put\\\", \\\"delete\\\", \\\"patch\\\", \\\"options\\\", \\\"head\\\", \\\"trace\\\", \\\"listen\\\", \\\"checkURLAsync\\\", \\\"websocketAsync\\\"}, fs = {\\\"complete\\\", \\\"isDriveRoot\\\"}}\\\
3851for k,v in pairs(delete) do for _,a in ipairs(v) do _G[k][a] = nil end end\\\
3852_G._HOST = _G._HOST .. \\\" (UnBIOS)\\\" \\\
3853-- Set up TLCO\\\
3854-- This functions by crashing `rednet.run` by removing `os.pullEventRaw`. Normally\\\
3855-- this would cause `parallel` to throw an error, but we replace `error` with an\\\
3856-- empty placeholder to let it continue and return without throwing. This results\\\
3857-- in the `pcall` returning successfully, preventing the error-displaying code\\\
3858-- from running - essentially making it so that `os.shutdown` is called immediately\\\
3859-- after the new BIOS exits.\\\
3860--\\\
3861-- From there, the setup code is placed in `term.native` since it's the first\\\
3862-- thing called after `parallel` exits. This loads the new BIOS and prepares it\\\
3863-- for execution. Finally, it overwrites `os.shutdown` with the new function to\\\
3864-- allow it to be the last function called in the original BIOS, and returns.\\\
3865-- From there execution continues, calling the `term.redirect` dummy, skipping\\\
3866-- over the error-handling code (since `pcall` returned ok), and calling\\\
3867-- `os.shutdown()`. The real `os.shutdown` is re-added, and the new BIOS is tail\\\
3868-- called, which effectively makes it run as the main chunk.\\\
3869local olderror = error\\\
3870_G.error = function() end\\\
3871_G.term.redirect = function() end\\\
3872function _G.term.native()\\\
3873 _G.term.native = nil\\\
3874 _G.term.redirect = nil\\\
3875 _G.error = olderror\\\
3876 term.setBackgroundColor(32768)\\\
3877 term.setTextColor(1)\\\
3878 term.setCursorPos(1, 1)\\\
3879 term.setCursorBlink(true)\\\
3880 term.clear()\\\
3881 local file = fs.open(\\\"boot/bios.lua\\\", \\\"r\\\")\\\
3882 if file == nil then\\\
3883 term.setCursorBlink(false)\\\
3884 term.setTextColor(16384)\\\
3885 term.write(\\\"Could not find /boot/bios.lua. UnBIOS cannot continue.\\\")\\\
3886 term.setCursorPos(1, 2)\\\
3887 term.write(\\\"Press any key to continue\\\")\\\
3888 coroutine.yield(\\\"key\\\")\\\
3889 os.shutdown()\\\
3890 end\\\
3891 local fn, err = loadstring(file.readAll(), \\\"@bios.lua\\\")\\\
3892 file.close()\\\
3893 if fn == nil then\\\
3894 term.setCursorBlink(false)\\\
3895 term.setTextColor(16384)\\\
3896 term.write(\\\"Could not load /bios.lua. UnBIOS cannot continue.\\\")\\\
3897 term.setCursorPos(1, 2)\\\
3898 term.write(err)\\\
3899 term.setCursorPos(1, 3)\\\
3900 term.write(\\\"Press any key to continue\\\")\\\
3901 coroutine.yield(\\\"key\\\")\\\
3902 os.shutdown()\\\
3903 end\\\
3904 setfenv(fn, _G)\\\
3905 local oldshutdown = os.shutdown\\\
3906 os.shutdown = function()\\\
3907 os.shutdown = oldshutdown\\\
3908 return fn()\\\
3909 end\\\
3910end\\\
3911if debug then\\\
3912 -- Restore functions that were overwritten in the BIOS\\\
3913 -- Apparently this has to be done *after* redefining term.native\\\
3914 local function restoreValue(tab, idx, name, hint)\\\
3915 local i, key, value = 1, debug.getupvalue(tab[idx], hint)\\\
3916 while key ~= name and key ~= nil do\\\
3917 key, value = debug.getupvalue(tab[idx], i)\\\
3918 i=i+1\\\
3919 end\\\
3920 tab[idx] = value or tab[idx]\\\
3921 end\\\
3922 restoreValue(_G, \\\"loadstring\\\", \\\"nativeloadstring\\\", 1)\\\
3923 restoreValue(_G, \\\"load\\\", \\\"nativeload\\\", 5)\\\
3924 restoreValue(http, \\\"request\\\", \\\"nativeHTTPRequest\\\", 3)\\\
3925 restoreValue(os, \\\"shutdown\\\", \\\"nativeShutdown\\\", 1)\\\
3926 restoreValue(os, \\\"reboot\\\", \\\"nativeReboot\\\", 1)\\\
3927 if turtle then\\\
3928 restoreValue(turtle, \\\"equipLeft\\\", \\\"v\\\", 1)\\\
3929 restoreValue(turtle, \\\"equipRight\\\", \\\"v\\\", 1)\\\
3930 end\\\
3931 do\\\
3932 local i, key, value = 1, debug.getupvalue(peripheral.isPresent, 2)\\\
3933 while key ~= \\\"native\\\" and key ~= nil do\\\
3934 key, value = debug.getupvalue(peripheral.isPresent, i)\\\
3935 i=i+1\\\
3936 end\\\
3937 _G.peripheral = value or peripheral\\\
3938 end\\\
3939end\\\
3940coroutine.yield()\",\
3941 Path = \"startup.lua\",\
3942 },\
3943}"
3944 local Dirs = {
3945 {
3946 Path = "boot",
3947 },
3948 {
3949 Path = "boot/apis",
3950 },
3951 {
3952 Path = "boot/logs",
3953 },
3954 {
3955 Path = "boot/modules",
3956 },
3957}
3958 programs = textutils.unserialise(programs)
3959 for _,v in pairs(Dirs) do
3960 if Path
3961 then
3962 fs.makeDir(fs.combine(Path,v.Path))
3963 else
3964 fs.makeDir(v.Path)
3965 end
3966 end
3967 for _,v in pairs(programs) do
3968 local file,mess
3969 if Path
3970 then
3971 file,mess = fs.open(fs.combine(Path,v.Path),"w")
3972 else
3973 file,mess = fs.open(v.Path,"w")
3974 end
3975 if not file
3976 then
3977 error(mess,0)
3978 end
3979 file.write(v.func)
3980 file.close()
3981 end
3982
3983