DorianH935

os.sys

Dec 20th, 2025
35
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 20.65 KB | None | 0 0
  1. -- OS.SYS - Core system library for DOS-like OpenComputers OS
  2. -- All system functions are stored in the global 'os' table
  3.  
  4. os = {}
  5. local component = component
  6. local computer = computer
  7.  
  8. -- ==================== COMPONENT HELPERS ====================
  9. os.component = {}
  10.  
  11. function os.component.get(address, ctype)
  12. if not address then return nil end
  13. if #address < 36 then
  14. for addr in component.list(ctype, true) do
  15. if addr:sub(1, #address) == address then
  16. return addr
  17. end
  18. end
  19. return nil
  20. end
  21. return address
  22. end
  23.  
  24. function os.component.getPrimary(ctype)
  25. local addr = component.list(ctype, true)()
  26. if addr then
  27. return component.proxy(addr)
  28. end
  29. return nil
  30. end
  31.  
  32. -- ==================== DISPLAY/GPU MODULE ====================
  33. os.display = {}
  34.  
  35. local gpu = os.component.getPrimary("gpu")
  36. local screen = os.component.getPrimary("screen")
  37.  
  38. os.display.gpu = gpu
  39. os.display.screen = screen
  40. os.display.cursorX = 1
  41. os.display.cursorY = 1
  42.  
  43. function os.display.clear()
  44. if gpu then
  45. local w, h = gpu.getResolution()
  46. gpu.fill(1, 1, w, h, " ")
  47. os.display.cursorX = 1
  48. os.display.cursorY = 1
  49. end
  50. end
  51.  
  52. function os.display.write(text, x, y)
  53. if not gpu then return end
  54.  
  55. text = tostring(text)
  56.  
  57. if x and y then
  58. os.display.cursorX = x
  59. os.display.cursorY = y
  60. end
  61.  
  62. local w, h = gpu.getResolution()
  63.  
  64. for i = 1, #text do
  65. local char = text:sub(i, i)
  66.  
  67. if char == "\n" then
  68. os.display.cursorY = os.display.cursorY + 1
  69. os.display.cursorX = 1
  70. if os.display.cursorY > h then
  71. gpu.copy(1, 2, w, h - 1, 0, -1)
  72. gpu.fill(1, h, w, 1, " ")
  73. os.display.cursorY = h
  74. end
  75. else
  76. if os.display.cursorX > w then
  77. os.display.cursorX = 1
  78. os.display.cursorY = os.display.cursorY + 1
  79. if os.display.cursorY > h then
  80. gpu.copy(1, 2, w, h - 1, 0, -1)
  81. gpu.fill(1, h, w, 1, " ")
  82. os.display.cursorY = h
  83. end
  84. end
  85. gpu.set(os.display.cursorX, os.display.cursorY, char)
  86. os.display.cursorX = os.display.cursorX + 1
  87. end
  88. end
  89. end
  90.  
  91. function os.display.getResolution()
  92. if gpu then
  93. return gpu.getResolution()
  94. end
  95. return 50, 16
  96. end
  97.  
  98. function os.display.setResolution(w, h)
  99. if gpu then
  100. return gpu.setResolution(w, h)
  101. end
  102. return false
  103. end
  104.  
  105. function os.display.setForeground(color)
  106. if gpu then
  107. return gpu.setForeground(color)
  108. end
  109. end
  110.  
  111. function os.display.setBackground(color)
  112. if gpu then
  113. return gpu.setBackground(color)
  114. end
  115. end
  116.  
  117. -- ==================== KEYBOARD/INPUT MODULE ====================
  118. os.keyboard = {}
  119.  
  120. local keyboard = os.component.getPrimary("keyboard")
  121. os.keyboard.keyboard = keyboard
  122.  
  123. function os.keyboard.isControl(char)
  124. return type(char) == "number" and (char < 0x20 or (char >= 0x7F and char <= 0x9F))
  125. end
  126.  
  127. function os.keyboard.isShiftDown()
  128. if keyboard then
  129. return keyboard.isShiftDown()
  130. end
  131. return false
  132. end
  133.  
  134. function os.keyboard.isControlDown()
  135. if keyboard then
  136. return keyboard.isControlDown()
  137. end
  138. return false
  139. end
  140.  
  141. function os.keyboard.isAltDown()
  142. if keyboard then
  143. return keyboard.isAltDown()
  144. end
  145. return false
  146. end
  147.  
  148. -- Key codes (from OpenOS)
  149. os.keyboard.keys = {
  150. ["1"] = 0x02, ["2"] = 0x03, ["3"] = 0x04, ["4"] = 0x05, ["5"] = 0x06,
  151. ["6"] = 0x07, ["7"] = 0x08, ["8"] = 0x09, ["9"] = 0x0A, ["0"] = 0x0B,
  152. a = 0x1E, b = 0x30, c = 0x2E, d = 0x20, e = 0x12, f = 0x21, g = 0x22,
  153. h = 0x23, i = 0x17, j = 0x24, k = 0x25, l = 0x26, m = 0x32, n = 0x31,
  154. o = 0x18, p = 0x19, q = 0x10, r = 0x13, s = 0x1F, t = 0x14, u = 0x16,
  155. v = 0x2F, w = 0x11, x = 0x2D, y = 0x15, z = 0x2C,
  156. enter = 0x1C, back = 0x0E, tab = 0x0F, space = 0x39,
  157. lshift = 0x2A, rshift = 0x36, lcontrol = 0x1D, rcontrol = 0x9D,
  158. }
  159.  
  160. -- ==================== FILESYSTEM MODULE ====================
  161. os.fs = {}
  162.  
  163. local bootfs = component.proxy(computer.getBootAddress())
  164. os.fs.bootfs = bootfs
  165. os.fs.drives = {} -- Drive letter assignments
  166. os.fs.drives["A"] = bootfs -- Boot drive is always A:
  167. os.fs.currentDrive = "A"
  168.  
  169. function os.fs.setDrive(letter, address)
  170. letter = string.upper(letter)
  171. if letter == "A" then
  172. return false, "Drive A: is reserved for boot disk"
  173. end
  174. if address then
  175. local proxy = component.proxy(address)
  176. if proxy then
  177. os.fs.drives[letter] = proxy
  178. os.fs.saveDriveConfig()
  179. return true
  180. end
  181. return false, "Invalid component address"
  182. else
  183. os.fs.drives[letter] = nil
  184. os.fs.saveDriveConfig()
  185. return true
  186. end
  187. end
  188.  
  189. function os.fs.saveDriveConfig()
  190. local config = {}
  191. for letter, proxy in pairs(os.fs.drives) do
  192. if letter ~= "A" then -- Don't save boot drive
  193. config[letter] = proxy.address
  194. end
  195. end
  196. local data = "return " .. os.serialize(config)
  197. local handle = bootfs.open("DRIVES.CFG", "w")
  198. if handle then
  199. bootfs.write(handle, data)
  200. bootfs.close(handle)
  201. end
  202. end
  203.  
  204. function os.fs.loadDriveConfig()
  205. if bootfs.exists("DRIVES.CFG") then
  206. local handle = bootfs.open("DRIVES.CFG", "r")
  207. if handle then
  208. local data = ""
  209. repeat
  210. local chunk = bootfs.read(handle, math.huge)
  211. data = data .. (chunk or "")
  212. until not chunk
  213. bootfs.close(handle)
  214.  
  215. local func, err = load(data, "=DRIVES.CFG", "t", {})
  216. if func then
  217. local ok, config = pcall(func)
  218. if ok and type(config) == "table" then
  219. for letter, address in pairs(config) do
  220. os.fs.setDrive(letter, address)
  221. end
  222. end
  223. end
  224. end
  225. end
  226. end
  227.  
  228. function os.fs.getDrive(letter)
  229. letter = string.upper(letter)
  230. return os.fs.drives[letter]
  231. end
  232.  
  233. function os.fs.listDrives()
  234. local list = {}
  235. for letter, proxy in pairs(os.fs.drives) do
  236. table.insert(list, {letter = letter, address = proxy.address})
  237. end
  238. return list
  239. end
  240.  
  241. function os.fs.getCurrentDrive()
  242. return os.fs.currentDrive
  243. end
  244.  
  245. function os.fs.setCurrentDrive(letter)
  246. letter = string.upper(letter)
  247. if os.fs.drives[letter] then
  248. os.fs.currentDrive = letter
  249. return true
  250. end
  251. return false, "Drive not found"
  252. end
  253.  
  254. function os.fs.getCurrentProxy()
  255. local drive = os.fs.drives[os.fs.currentDrive]
  256. if drive then return drive end
  257.  
  258. -- Check if it's a tape drive
  259. local tape = os.tape.tapes[os.fs.currentDrive]
  260. if tape then return tape end
  261.  
  262. return bootfs
  263. end
  264.  
  265. function os.fs.isTapeDrive(letter)
  266. letter = letter or os.fs.currentDrive
  267. return os.tape.tapes[string.upper(letter)] ~= nil
  268. end
  269.  
  270. function os.fs.list(path)
  271. path = path or "/"
  272.  
  273. -- Check if current drive is a tape
  274. if os.fs.isTapeDrive() then
  275. local tape = os.fs.getCurrentProxy()
  276. return os.tapefs.list(tape, path)
  277. end
  278.  
  279. local proxy = os.fs.getCurrentProxy()
  280. if not proxy then
  281. return nil, "No filesystem available"
  282. end
  283. -- Check if the component is still valid
  284. local ok, result = pcall(function()
  285. local handle = proxy.list(path)
  286. if not handle then
  287. return nil, "Failed to list directory"
  288. end
  289. local entries = {}
  290. -- proxy.list returns an iterator function, not a table
  291. if type(handle) == "function" then
  292. for entry in handle do
  293. table.insert(entries, entry)
  294. end
  295. else
  296. -- In case it returns a table directly
  297. return handle
  298. end
  299. return entries
  300. end)
  301.  
  302. if not ok then
  303. return nil, "Drive not available"
  304. end
  305. return result
  306. end
  307.  
  308. function os.fs.exists(path)
  309. if os.fs.isTapeDrive() then
  310. local tape = os.fs.getCurrentProxy()
  311. return os.tapefs.exists(tape, path)
  312. end
  313.  
  314. local proxy = os.fs.getCurrentProxy()
  315. if not proxy then return false end
  316. local ok, result = pcall(function() return proxy.exists(path) end)
  317. return ok and result
  318. end
  319.  
  320. function os.fs.isDirectory(path)
  321. if os.fs.isTapeDrive() then
  322. return false -- Tapes don't have directories yet
  323. end
  324.  
  325. local proxy = os.fs.getCurrentProxy()
  326. if not proxy then return false end
  327. local ok, result = pcall(function() return proxy.isDirectory(path) end)
  328. return ok and result
  329. end
  330.  
  331. function os.fs.size(path)
  332. if os.fs.isTapeDrive() then
  333. local tape = os.fs.getCurrentProxy()
  334. return os.tapefs.size(tape, path)
  335. end
  336.  
  337. local proxy = os.fs.getCurrentProxy()
  338. if not proxy then return 0 end
  339. local ok, result = pcall(function() return proxy.size(path) end)
  340. return ok and result or 0
  341. end
  342.  
  343. function os.fs.lastModified(path)
  344. local proxy = os.fs.getCurrentProxy()
  345. if not proxy then return 0 end
  346. local ok, result = pcall(function() return proxy.lastModified(path) end)
  347. return ok and result or 0
  348. end
  349.  
  350. function os.fs.remove(path)
  351. if os.fs.isTapeDrive() then
  352. local tape = os.fs.getCurrentProxy()
  353. return os.tapefs.remove(tape, path)
  354. end
  355.  
  356. local proxy = os.fs.getCurrentProxy()
  357. if not proxy then return false, "No filesystem available" end
  358. local ok, result = pcall(function() return proxy.remove(path) end)
  359. if not ok then return false, "Drive not available" end
  360. return result
  361. end
  362.  
  363. function os.fs.makeDirectory(path)
  364. local proxy = os.fs.getCurrentProxy()
  365. if not proxy then return false, "No filesystem available" end
  366. local ok, result = pcall(function() return proxy.makeDirectory(path) end)
  367. if not ok then return false, "Drive not available" end
  368. return result
  369. end
  370.  
  371. function os.fs.rename(from, to)
  372. local proxy = os.fs.getCurrentProxy()
  373. if not proxy then return false, "No filesystem available" end
  374. local ok, result = pcall(function() return proxy.rename(from, to) end)
  375. if not ok then return false, "Drive not available" end
  376. return result
  377. end
  378.  
  379. function os.fs.open(path, mode)
  380. local proxy = os.fs.getCurrentProxy()
  381. if not proxy then return nil, "No filesystem available" end
  382. local ok, result = pcall(function() return proxy.open(path, mode or "r") end)
  383. if not ok then return nil, "Drive not available" end
  384. return result
  385. end
  386.  
  387. function os.fs.close(handle)
  388. local proxy = os.fs.getCurrentProxy()
  389. if not proxy then return false end
  390. local ok, result = pcall(function() return proxy.close(handle) end)
  391. return ok and result
  392. end
  393.  
  394. function os.fs.read(handle, count)
  395. local proxy = os.fs.getCurrentProxy()
  396. if not proxy then return nil end
  397. local ok, result = pcall(function() return proxy.read(handle, count or math.huge) end)
  398. if not ok then return nil end
  399. return result
  400. end
  401.  
  402. function os.fs.write(handle, data)
  403. local proxy = os.fs.getCurrentProxy()
  404. if not proxy then return false end
  405. local ok, result = pcall(function() return proxy.write(handle, data) end)
  406. return ok and result
  407. end
  408.  
  409. function os.fs.readAll(path)
  410. if os.fs.isTapeDrive() then
  411. local tape = os.fs.getCurrentProxy()
  412. return os.tapefs.readFile(tape, path)
  413. end
  414.  
  415. local handle, reason = os.fs.open(path, "r")
  416. if not handle then
  417. return nil, reason
  418. end
  419. local data = ""
  420. repeat
  421. local chunk = os.fs.read(handle, math.huge)
  422. data = data .. (chunk or "")
  423. until not chunk
  424. os.fs.close(handle)
  425. return data
  426. end
  427.  
  428. function os.fs.writeAll(path, data)
  429. if os.fs.isTapeDrive() then
  430. local tape = os.fs.getCurrentProxy()
  431. return os.tapefs.writeFile(tape, path, data)
  432. end
  433.  
  434. local handle, reason = os.fs.open(path, "w")
  435. if not handle then
  436. return nil, reason
  437. end
  438. os.fs.write(handle, data)
  439. os.fs.close(handle)
  440. return true
  441. end
  442.  
  443. -- ==================== NETWORK MODULE ====================
  444. os.network = {}
  445.  
  446. local modem = os.component.getPrimary("modem")
  447. local internet = os.component.getPrimary("internet")
  448. local tunnel = os.component.getPrimary("tunnel")
  449.  
  450. os.network.modem = modem
  451. os.network.internet = internet
  452. os.network.tunnel = tunnel
  453.  
  454. function os.network.broadcast(port, ...)
  455. if modem then
  456. return modem.broadcast(port, ...)
  457. end
  458. return false
  459. end
  460.  
  461. function os.network.send(address, port, ...)
  462. if modem then
  463. return modem.send(address, port, ...)
  464. end
  465. return false
  466. end
  467.  
  468. function os.network.open(port)
  469. if modem then
  470. return modem.open(port)
  471. end
  472. return false
  473. end
  474.  
  475. function os.network.close(port)
  476. if modem then
  477. return modem.close(port)
  478. end
  479. return false
  480. end
  481.  
  482. function os.network.isOpen(port)
  483. if modem then
  484. return modem.isOpen(port)
  485. end
  486. return false
  487. end
  488.  
  489. function os.network.httpRequest(url, postData, headers)
  490. if internet then
  491. return internet.request(url, postData, headers)
  492. end
  493. return nil, "No internet card"
  494. end
  495.  
  496. function os.network.tunnelSend(...)
  497. if tunnel then
  498. return tunnel.send(...)
  499. end
  500. return false
  501. end
  502.  
  503. -- ==================== TAPE DRIVE MODULE ====================
  504. os.tape = {}
  505.  
  506. os.tape.tapes = {} -- Drive letter assignments for tapes
  507. os.tape.currentTape = nil
  508.  
  509. function os.tape.setTape(letter, address)
  510. letter = string.upper(letter)
  511. if address then
  512. local proxy = component.proxy(address)
  513. if proxy and proxy.type == "tape_drive" then
  514. os.tape.tapes[letter] = proxy
  515. os.tape.saveTapeConfig()
  516. return true
  517. end
  518. return false, "Invalid tape drive address"
  519. else
  520. os.tape.tapes[letter] = nil
  521. os.tape.saveTapeConfig()
  522. return true
  523. end
  524. end
  525.  
  526. function os.tape.saveTapeConfig()
  527. local config = {}
  528. for letter, proxy in pairs(os.tape.tapes) do
  529. config[letter] = proxy.address
  530. end
  531. local data = "return " .. os.serialize(config)
  532. local handle = bootfs.open("TAPES.CFG", "w")
  533. if handle then
  534. bootfs.write(handle, data)
  535. bootfs.close(handle)
  536. end
  537. end
  538.  
  539. function os.tape.loadTapeConfig()
  540. if bootfs.exists("TAPES.CFG") then
  541. local handle = bootfs.open("TAPES.CFG", "r")
  542. if handle then
  543. local data = ""
  544. repeat
  545. local chunk = bootfs.read(handle, math.huge)
  546. data = data .. (chunk or "")
  547. until not chunk
  548. bootfs.close(handle)
  549.  
  550. local func, err = load(data, "=TAPES.CFG", "t", {})
  551. if func then
  552. local ok, config = pcall(func)
  553. if ok and type(config) == "table" then
  554. for letter, address in pairs(config) do
  555. os.tape.setTape(letter, address)
  556. end
  557. end
  558. end
  559. end
  560. end
  561. end
  562.  
  563. function os.tape.getTape(letter)
  564. letter = string.upper(letter)
  565. return os.tape.tapes[letter]
  566. end
  567.  
  568. function os.tape.listTapes()
  569. local list = {}
  570. for letter, proxy in pairs(os.tape.tapes) do
  571. table.insert(list, {letter = letter, address = proxy.address})
  572. end
  573. return list
  574. end
  575.  
  576. function os.tape.setCurrentTape(letter)
  577. letter = string.upper(letter)
  578. if os.tape.tapes[letter] then
  579. os.tape.currentTape = letter
  580. os.tape.drive = os.tape.tapes[letter]
  581. return true
  582. end
  583. return false, "Tape not found"
  584. end
  585.  
  586. function os.tape.getCurrentTape()
  587. return os.tape.currentTape
  588. end
  589.  
  590. local tape = os.component.getPrimary("tape_drive")
  591. os.tape.drive = tape
  592.  
  593. function os.tape.play()
  594. if tape then
  595. return tape.play()
  596. end
  597. end
  598.  
  599. function os.tape.stop()
  600. if tape then
  601. return tape.stop()
  602. end
  603. end
  604.  
  605. function os.tape.pause()
  606. if tape then
  607. return tape.stop()
  608. end
  609. end
  610.  
  611. function os.tape.seek(position)
  612. if tape then
  613. return tape.seek(position)
  614. end
  615. end
  616.  
  617. function os.tape.read(count)
  618. if tape then
  619. return tape.read(count or 8192)
  620. end
  621. end
  622.  
  623. function os.tape.write(data)
  624. if tape then
  625. return tape.write(data)
  626. end
  627. end
  628.  
  629. function os.tape.getSize()
  630. if tape then
  631. return tape.getSize()
  632. end
  633. return 0
  634. end
  635.  
  636. function os.tape.getState()
  637. if tape then
  638. return tape.getState()
  639. end
  640. return "STOPPED"
  641. end
  642.  
  643. function os.tape.getPosition()
  644. if tape then
  645. return tape.getPosition()
  646. end
  647. return 0
  648. end
  649.  
  650. function os.tape.setSpeed(speed)
  651. if tape then
  652. return tape.setSpeed(speed)
  653. end
  654. end
  655.  
  656. function os.tape.setVolume(volume)
  657. if tape then
  658. return tape.setVolume(volume)
  659. end
  660. end
  661.  
  662. -- ==================== SOUND CARD MODULE ====================
  663. os.sound = {}
  664.  
  665. local sound = os.component.getPrimary("sound")
  666. os.sound.card = sound
  667.  
  668. function os.sound.setWave(channel, wave)
  669. if sound then
  670. return sound.setWave(channel, wave)
  671. end
  672. end
  673.  
  674. function os.sound.setFrequency(channel, freq)
  675. if sound then
  676. return sound.setFrequency(channel, freq)
  677. end
  678. end
  679.  
  680. function os.sound.open(channel)
  681. if sound then
  682. return sound.open(channel)
  683. end
  684. end
  685.  
  686. function os.sound.close(channel)
  687. if sound then
  688. return sound.close(channel)
  689. end
  690. end
  691.  
  692. function os.sound.setVolume(channel, volume)
  693. if sound then
  694. return sound.setVolume(channel, volume)
  695. end
  696. end
  697.  
  698. function os.sound.setDelay(delay)
  699. if sound then
  700. return sound.setDelay(delay)
  701. end
  702. end
  703.  
  704. function os.sound.process()
  705. if sound then
  706. return sound.process()
  707. end
  708. end
  709.  
  710. function os.sound.beep(frequency, duration)
  711. if sound then
  712. os.sound.setWave(1, os.sound.modes.square)
  713. os.sound.open(1)
  714. os.sound.setFrequency(1, frequency or 1000)
  715. os.sound.setVolume(1, 1.0)
  716. computer.pullSignal(duration or 0.2)
  717. os.sound.close(1)
  718. end
  719. end
  720.  
  721. os.sound.modes = {
  722. sine = 1,
  723. square = 2,
  724. triangle = 3,
  725. sawtooth = 4,
  726. }
  727.  
  728. -- ==================== EVENT/SIGNAL MODULE ====================
  729. os.event = {}
  730.  
  731. function os.event.pull(timeout, filter)
  732. local deadline = computer.uptime() + (timeout or math.huge)
  733. repeat
  734. local signal = table.pack(computer.pullSignal(deadline - computer.uptime()))
  735. if signal.n > 0 then
  736. if not filter or signal[1] == filter then
  737. return table.unpack(signal, 1, signal.n)
  738. end
  739. end
  740. until computer.uptime() >= deadline
  741. return nil
  742. end
  743.  
  744. function os.event.push(...)
  745. return computer.pushSignal(...)
  746. end
  747.  
  748. -- ==================== SYSTEM UTILITIES ====================
  749. os.system = {}
  750.  
  751. function os.system.shutdown(reboot)
  752. if reboot then
  753. computer.shutdown(true)
  754. else
  755. computer.shutdown()
  756. end
  757. end
  758.  
  759. function os.system.uptime()
  760. return computer.uptime()
  761. end
  762.  
  763. function os.system.freeMemory()
  764. return computer.freeMemory()
  765. end
  766.  
  767. function os.system.totalMemory()
  768. return computer.totalMemory()
  769. end
  770.  
  771. function os.system.energy()
  772. return computer.energy()
  773. end
  774.  
  775. function os.system.maxEnergy()
  776. return computer.maxEnergy()
  777. end
  778.  
  779. function os.system.sleep(seconds)
  780. local deadline = computer.uptime() + (seconds or 0)
  781. repeat
  782. computer.pullSignal(deadline - computer.uptime())
  783. until computer.uptime() >= deadline
  784. end
  785.  
  786. function os.system.beep(frequency, duration)
  787. computer.beep(frequency, duration)
  788. end
  789.  
  790. -- ==================== STRING UTILITIES ====================
  791. os.string = {}
  792.  
  793. function os.string.split(str, sep)
  794. local parts = {}
  795. local pattern = string.format("([^%s]+)", sep or " ")
  796. for part in string.gmatch(str, pattern) do
  797. table.insert(parts, part)
  798. end
  799. return parts
  800. end
  801.  
  802. function os.string.trim(str)
  803. return string.match(str, "^%s*(.-)%s*$")
  804. end
  805.  
  806. function os.string.startsWith(str, prefix)
  807. return string.sub(str, 1, #prefix) == prefix
  808. end
  809.  
  810. function os.string.endsWith(str, suffix)
  811. return string.sub(str, -#suffix) == suffix
  812. end
  813.  
  814. -- ==================== SERIALIZATION ====================
  815. function os.serialize(value, indent)
  816. indent = indent or 0
  817. local t = type(value)
  818.  
  819. if t == "number" or t == "boolean" then
  820. return tostring(value)
  821. elseif t == "string" then
  822. return string.format("%q", value)
  823. elseif t == "table" then
  824. local parts = {}
  825. local spaces = string.rep(" ", indent)
  826. table.insert(parts, "{")
  827. for k, v in pairs(value) do
  828. local key
  829. if type(k) == "string" and k:match("^[%a_][%w_]*$") then
  830. key = k
  831. else
  832. key = "[" .. os.serialize(k) .. "]"
  833. end
  834. table.insert(parts, spaces .. " " .. key .. " = " .. os.serialize(v, indent + 1) .. ",")
  835. end
  836. table.insert(parts, spaces .. "}")
  837. return table.concat(parts, "\n")
  838. else
  839. return "nil"
  840. end
  841. end
  842.  
  843. -- ==================== PATH UTILITIES ====================
  844. os.path = {}
  845.  
  846. function os.path.concat(...)
  847. local parts = {...}
  848. local result = ""
  849. for i, part in ipairs(parts) do
  850. if part ~= "" then
  851. if result ~= "" and not result:match("/$") then
  852. result = result .. "/"
  853. end
  854. result = result .. part
  855. end
  856. end
  857. return result
  858. end
  859.  
  860. function os.path.split(path)
  861. local dir, file = path:match("^(.+)/([^/]+)$")
  862. if not dir then
  863. return "/", path
  864. end
  865. return dir, file
  866. end
  867.  
  868. function os.path.name(path)
  869. return path:match("[^/]+$") or path
  870. end
  871.  
  872. function os.path.extension(path)
  873. return path:match("%.([^./]+)$") or ""
  874. end
  875.  
  876. -- Initialize system
  877. if gpu then
  878. gpu.set(1, 1, "OS.SYS loaded successfully")
  879. end
  880.  
  881. -- Load saved drive configurations
  882. os.fs.loadDriveConfig()
  883. os.tape.loadTapeConfig()
  884.  
  885. return true
Advertisement
Add Comment
Please, Sign In to add comment