Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- OS.SYS - Core system library for DOS-like OpenComputers OS
- -- All system functions are stored in the global 'os' table
- os = {}
- local component = component
- local computer = computer
- -- ==================== COMPONENT HELPERS ====================
- os.component = {}
- function os.component.get(address, ctype)
- if not address then return nil end
- if #address < 36 then
- for addr in component.list(ctype, true) do
- if addr:sub(1, #address) == address then
- return addr
- end
- end
- return nil
- end
- return address
- end
- function os.component.getPrimary(ctype)
- local addr = component.list(ctype, true)()
- if addr then
- return component.proxy(addr)
- end
- return nil
- end
- -- ==================== DISPLAY/GPU MODULE ====================
- os.display = {}
- local gpu = os.component.getPrimary("gpu")
- local screen = os.component.getPrimary("screen")
- os.display.gpu = gpu
- os.display.screen = screen
- os.display.cursorX = 1
- os.display.cursorY = 1
- function os.display.clear()
- if gpu then
- local w, h = gpu.getResolution()
- gpu.fill(1, 1, w, h, " ")
- os.display.cursorX = 1
- os.display.cursorY = 1
- end
- end
- function os.display.write(text, x, y)
- if not gpu then return end
- text = tostring(text)
- if x and y then
- os.display.cursorX = x
- os.display.cursorY = y
- end
- local w, h = gpu.getResolution()
- for i = 1, #text do
- local char = text:sub(i, i)
- if char == "\n" then
- os.display.cursorY = os.display.cursorY + 1
- os.display.cursorX = 1
- if os.display.cursorY > h then
- gpu.copy(1, 2, w, h - 1, 0, -1)
- gpu.fill(1, h, w, 1, " ")
- os.display.cursorY = h
- end
- else
- if os.display.cursorX > w then
- os.display.cursorX = 1
- os.display.cursorY = os.display.cursorY + 1
- if os.display.cursorY > h then
- gpu.copy(1, 2, w, h - 1, 0, -1)
- gpu.fill(1, h, w, 1, " ")
- os.display.cursorY = h
- end
- end
- gpu.set(os.display.cursorX, os.display.cursorY, char)
- os.display.cursorX = os.display.cursorX + 1
- end
- end
- end
- function os.display.getResolution()
- if gpu then
- return gpu.getResolution()
- end
- return 50, 16
- end
- function os.display.setResolution(w, h)
- if gpu then
- return gpu.setResolution(w, h)
- end
- return false
- end
- function os.display.setForeground(color)
- if gpu then
- return gpu.setForeground(color)
- end
- end
- function os.display.setBackground(color)
- if gpu then
- return gpu.setBackground(color)
- end
- end
- -- ==================== KEYBOARD/INPUT MODULE ====================
- os.keyboard = {}
- local keyboard = os.component.getPrimary("keyboard")
- os.keyboard.keyboard = keyboard
- function os.keyboard.isControl(char)
- return type(char) == "number" and (char < 0x20 or (char >= 0x7F and char <= 0x9F))
- end
- function os.keyboard.isShiftDown()
- if keyboard then
- return keyboard.isShiftDown()
- end
- return false
- end
- function os.keyboard.isControlDown()
- if keyboard then
- return keyboard.isControlDown()
- end
- return false
- end
- function os.keyboard.isAltDown()
- if keyboard then
- return keyboard.isAltDown()
- end
- return false
- end
- -- Key codes (from OpenOS)
- os.keyboard.keys = {
- ["1"] = 0x02, ["2"] = 0x03, ["3"] = 0x04, ["4"] = 0x05, ["5"] = 0x06,
- ["6"] = 0x07, ["7"] = 0x08, ["8"] = 0x09, ["9"] = 0x0A, ["0"] = 0x0B,
- a = 0x1E, b = 0x30, c = 0x2E, d = 0x20, e = 0x12, f = 0x21, g = 0x22,
- h = 0x23, i = 0x17, j = 0x24, k = 0x25, l = 0x26, m = 0x32, n = 0x31,
- o = 0x18, p = 0x19, q = 0x10, r = 0x13, s = 0x1F, t = 0x14, u = 0x16,
- v = 0x2F, w = 0x11, x = 0x2D, y = 0x15, z = 0x2C,
- enter = 0x1C, back = 0x0E, tab = 0x0F, space = 0x39,
- lshift = 0x2A, rshift = 0x36, lcontrol = 0x1D, rcontrol = 0x9D,
- }
- -- ==================== FILESYSTEM MODULE ====================
- os.fs = {}
- local bootfs = component.proxy(computer.getBootAddress())
- os.fs.bootfs = bootfs
- os.fs.drives = {} -- Drive letter assignments
- os.fs.drives["A"] = bootfs -- Boot drive is always A:
- os.fs.currentDrive = "A"
- function os.fs.setDrive(letter, address)
- letter = string.upper(letter)
- if letter == "A" then
- return false, "Drive A: is reserved for boot disk"
- end
- if address then
- local proxy = component.proxy(address)
- if proxy then
- os.fs.drives[letter] = proxy
- os.fs.saveDriveConfig()
- return true
- end
- return false, "Invalid component address"
- else
- os.fs.drives[letter] = nil
- os.fs.saveDriveConfig()
- return true
- end
- end
- function os.fs.saveDriveConfig()
- local config = {}
- for letter, proxy in pairs(os.fs.drives) do
- if letter ~= "A" then -- Don't save boot drive
- config[letter] = proxy.address
- end
- end
- local data = "return " .. os.serialize(config)
- local handle = bootfs.open("DRIVES.CFG", "w")
- if handle then
- bootfs.write(handle, data)
- bootfs.close(handle)
- end
- end
- function os.fs.loadDriveConfig()
- if bootfs.exists("DRIVES.CFG") then
- local handle = bootfs.open("DRIVES.CFG", "r")
- if handle then
- local data = ""
- repeat
- local chunk = bootfs.read(handle, math.huge)
- data = data .. (chunk or "")
- until not chunk
- bootfs.close(handle)
- local func, err = load(data, "=DRIVES.CFG", "t", {})
- if func then
- local ok, config = pcall(func)
- if ok and type(config) == "table" then
- for letter, address in pairs(config) do
- os.fs.setDrive(letter, address)
- end
- end
- end
- end
- end
- end
- function os.fs.getDrive(letter)
- letter = string.upper(letter)
- return os.fs.drives[letter]
- end
- function os.fs.listDrives()
- local list = {}
- for letter, proxy in pairs(os.fs.drives) do
- table.insert(list, {letter = letter, address = proxy.address})
- end
- return list
- end
- function os.fs.getCurrentDrive()
- return os.fs.currentDrive
- end
- function os.fs.setCurrentDrive(letter)
- letter = string.upper(letter)
- if os.fs.drives[letter] then
- os.fs.currentDrive = letter
- return true
- end
- return false, "Drive not found"
- end
- function os.fs.getCurrentProxy()
- local drive = os.fs.drives[os.fs.currentDrive]
- if drive then return drive end
- -- Check if it's a tape drive
- local tape = os.tape.tapes[os.fs.currentDrive]
- if tape then return tape end
- return bootfs
- end
- function os.fs.isTapeDrive(letter)
- letter = letter or os.fs.currentDrive
- return os.tape.tapes[string.upper(letter)] ~= nil
- end
- function os.fs.list(path)
- path = path or "/"
- -- Check if current drive is a tape
- if os.fs.isTapeDrive() then
- local tape = os.fs.getCurrentProxy()
- return os.tapefs.list(tape, path)
- end
- local proxy = os.fs.getCurrentProxy()
- if not proxy then
- return nil, "No filesystem available"
- end
- -- Check if the component is still valid
- local ok, result = pcall(function()
- local handle = proxy.list(path)
- if not handle then
- return nil, "Failed to list directory"
- end
- local entries = {}
- -- proxy.list returns an iterator function, not a table
- if type(handle) == "function" then
- for entry in handle do
- table.insert(entries, entry)
- end
- else
- -- In case it returns a table directly
- return handle
- end
- return entries
- end)
- if not ok then
- return nil, "Drive not available"
- end
- return result
- end
- function os.fs.exists(path)
- if os.fs.isTapeDrive() then
- local tape = os.fs.getCurrentProxy()
- return os.tapefs.exists(tape, path)
- end
- local proxy = os.fs.getCurrentProxy()
- if not proxy then return false end
- local ok, result = pcall(function() return proxy.exists(path) end)
- return ok and result
- end
- function os.fs.isDirectory(path)
- if os.fs.isTapeDrive() then
- return false -- Tapes don't have directories yet
- end
- local proxy = os.fs.getCurrentProxy()
- if not proxy then return false end
- local ok, result = pcall(function() return proxy.isDirectory(path) end)
- return ok and result
- end
- function os.fs.size(path)
- if os.fs.isTapeDrive() then
- local tape = os.fs.getCurrentProxy()
- return os.tapefs.size(tape, path)
- end
- local proxy = os.fs.getCurrentProxy()
- if not proxy then return 0 end
- local ok, result = pcall(function() return proxy.size(path) end)
- return ok and result or 0
- end
- function os.fs.lastModified(path)
- local proxy = os.fs.getCurrentProxy()
- if not proxy then return 0 end
- local ok, result = pcall(function() return proxy.lastModified(path) end)
- return ok and result or 0
- end
- function os.fs.remove(path)
- if os.fs.isTapeDrive() then
- local tape = os.fs.getCurrentProxy()
- return os.tapefs.remove(tape, path)
- end
- local proxy = os.fs.getCurrentProxy()
- if not proxy then return false, "No filesystem available" end
- local ok, result = pcall(function() return proxy.remove(path) end)
- if not ok then return false, "Drive not available" end
- return result
- end
- function os.fs.makeDirectory(path)
- local proxy = os.fs.getCurrentProxy()
- if not proxy then return false, "No filesystem available" end
- local ok, result = pcall(function() return proxy.makeDirectory(path) end)
- if not ok then return false, "Drive not available" end
- return result
- end
- function os.fs.rename(from, to)
- local proxy = os.fs.getCurrentProxy()
- if not proxy then return false, "No filesystem available" end
- local ok, result = pcall(function() return proxy.rename(from, to) end)
- if not ok then return false, "Drive not available" end
- return result
- end
- function os.fs.open(path, mode)
- local proxy = os.fs.getCurrentProxy()
- if not proxy then return nil, "No filesystem available" end
- local ok, result = pcall(function() return proxy.open(path, mode or "r") end)
- if not ok then return nil, "Drive not available" end
- return result
- end
- function os.fs.close(handle)
- local proxy = os.fs.getCurrentProxy()
- if not proxy then return false end
- local ok, result = pcall(function() return proxy.close(handle) end)
- return ok and result
- end
- function os.fs.read(handle, count)
- local proxy = os.fs.getCurrentProxy()
- if not proxy then return nil end
- local ok, result = pcall(function() return proxy.read(handle, count or math.huge) end)
- if not ok then return nil end
- return result
- end
- function os.fs.write(handle, data)
- local proxy = os.fs.getCurrentProxy()
- if not proxy then return false end
- local ok, result = pcall(function() return proxy.write(handle, data) end)
- return ok and result
- end
- function os.fs.readAll(path)
- if os.fs.isTapeDrive() then
- local tape = os.fs.getCurrentProxy()
- return os.tapefs.readFile(tape, path)
- end
- local handle, reason = os.fs.open(path, "r")
- if not handle then
- return nil, reason
- end
- local data = ""
- repeat
- local chunk = os.fs.read(handle, math.huge)
- data = data .. (chunk or "")
- until not chunk
- os.fs.close(handle)
- return data
- end
- function os.fs.writeAll(path, data)
- if os.fs.isTapeDrive() then
- local tape = os.fs.getCurrentProxy()
- return os.tapefs.writeFile(tape, path, data)
- end
- local handle, reason = os.fs.open(path, "w")
- if not handle then
- return nil, reason
- end
- os.fs.write(handle, data)
- os.fs.close(handle)
- return true
- end
- -- ==================== NETWORK MODULE ====================
- os.network = {}
- local modem = os.component.getPrimary("modem")
- local internet = os.component.getPrimary("internet")
- local tunnel = os.component.getPrimary("tunnel")
- os.network.modem = modem
- os.network.internet = internet
- os.network.tunnel = tunnel
- function os.network.broadcast(port, ...)
- if modem then
- return modem.broadcast(port, ...)
- end
- return false
- end
- function os.network.send(address, port, ...)
- if modem then
- return modem.send(address, port, ...)
- end
- return false
- end
- function os.network.open(port)
- if modem then
- return modem.open(port)
- end
- return false
- end
- function os.network.close(port)
- if modem then
- return modem.close(port)
- end
- return false
- end
- function os.network.isOpen(port)
- if modem then
- return modem.isOpen(port)
- end
- return false
- end
- function os.network.httpRequest(url, postData, headers)
- if internet then
- return internet.request(url, postData, headers)
- end
- return nil, "No internet card"
- end
- function os.network.tunnelSend(...)
- if tunnel then
- return tunnel.send(...)
- end
- return false
- end
- -- ==================== TAPE DRIVE MODULE ====================
- os.tape = {}
- os.tape.tapes = {} -- Drive letter assignments for tapes
- os.tape.currentTape = nil
- function os.tape.setTape(letter, address)
- letter = string.upper(letter)
- if address then
- local proxy = component.proxy(address)
- if proxy and proxy.type == "tape_drive" then
- os.tape.tapes[letter] = proxy
- os.tape.saveTapeConfig()
- return true
- end
- return false, "Invalid tape drive address"
- else
- os.tape.tapes[letter] = nil
- os.tape.saveTapeConfig()
- return true
- end
- end
- function os.tape.saveTapeConfig()
- local config = {}
- for letter, proxy in pairs(os.tape.tapes) do
- config[letter] = proxy.address
- end
- local data = "return " .. os.serialize(config)
- local handle = bootfs.open("TAPES.CFG", "w")
- if handle then
- bootfs.write(handle, data)
- bootfs.close(handle)
- end
- end
- function os.tape.loadTapeConfig()
- if bootfs.exists("TAPES.CFG") then
- local handle = bootfs.open("TAPES.CFG", "r")
- if handle then
- local data = ""
- repeat
- local chunk = bootfs.read(handle, math.huge)
- data = data .. (chunk or "")
- until not chunk
- bootfs.close(handle)
- local func, err = load(data, "=TAPES.CFG", "t", {})
- if func then
- local ok, config = pcall(func)
- if ok and type(config) == "table" then
- for letter, address in pairs(config) do
- os.tape.setTape(letter, address)
- end
- end
- end
- end
- end
- end
- function os.tape.getTape(letter)
- letter = string.upper(letter)
- return os.tape.tapes[letter]
- end
- function os.tape.listTapes()
- local list = {}
- for letter, proxy in pairs(os.tape.tapes) do
- table.insert(list, {letter = letter, address = proxy.address})
- end
- return list
- end
- function os.tape.setCurrentTape(letter)
- letter = string.upper(letter)
- if os.tape.tapes[letter] then
- os.tape.currentTape = letter
- os.tape.drive = os.tape.tapes[letter]
- return true
- end
- return false, "Tape not found"
- end
- function os.tape.getCurrentTape()
- return os.tape.currentTape
- end
- local tape = os.component.getPrimary("tape_drive")
- os.tape.drive = tape
- function os.tape.play()
- if tape then
- return tape.play()
- end
- end
- function os.tape.stop()
- if tape then
- return tape.stop()
- end
- end
- function os.tape.pause()
- if tape then
- return tape.stop()
- end
- end
- function os.tape.seek(position)
- if tape then
- return tape.seek(position)
- end
- end
- function os.tape.read(count)
- if tape then
- return tape.read(count or 8192)
- end
- end
- function os.tape.write(data)
- if tape then
- return tape.write(data)
- end
- end
- function os.tape.getSize()
- if tape then
- return tape.getSize()
- end
- return 0
- end
- function os.tape.getState()
- if tape then
- return tape.getState()
- end
- return "STOPPED"
- end
- function os.tape.getPosition()
- if tape then
- return tape.getPosition()
- end
- return 0
- end
- function os.tape.setSpeed(speed)
- if tape then
- return tape.setSpeed(speed)
- end
- end
- function os.tape.setVolume(volume)
- if tape then
- return tape.setVolume(volume)
- end
- end
- -- ==================== SOUND CARD MODULE ====================
- os.sound = {}
- local sound = os.component.getPrimary("sound")
- os.sound.card = sound
- function os.sound.setWave(channel, wave)
- if sound then
- return sound.setWave(channel, wave)
- end
- end
- function os.sound.setFrequency(channel, freq)
- if sound then
- return sound.setFrequency(channel, freq)
- end
- end
- function os.sound.open(channel)
- if sound then
- return sound.open(channel)
- end
- end
- function os.sound.close(channel)
- if sound then
- return sound.close(channel)
- end
- end
- function os.sound.setVolume(channel, volume)
- if sound then
- return sound.setVolume(channel, volume)
- end
- end
- function os.sound.setDelay(delay)
- if sound then
- return sound.setDelay(delay)
- end
- end
- function os.sound.process()
- if sound then
- return sound.process()
- end
- end
- function os.sound.beep(frequency, duration)
- if sound then
- os.sound.setWave(1, os.sound.modes.square)
- os.sound.open(1)
- os.sound.setFrequency(1, frequency or 1000)
- os.sound.setVolume(1, 1.0)
- computer.pullSignal(duration or 0.2)
- os.sound.close(1)
- end
- end
- os.sound.modes = {
- sine = 1,
- square = 2,
- triangle = 3,
- sawtooth = 4,
- }
- -- ==================== EVENT/SIGNAL MODULE ====================
- os.event = {}
- function os.event.pull(timeout, filter)
- local deadline = computer.uptime() + (timeout or math.huge)
- repeat
- local signal = table.pack(computer.pullSignal(deadline - computer.uptime()))
- if signal.n > 0 then
- if not filter or signal[1] == filter then
- return table.unpack(signal, 1, signal.n)
- end
- end
- until computer.uptime() >= deadline
- return nil
- end
- function os.event.push(...)
- return computer.pushSignal(...)
- end
- -- ==================== SYSTEM UTILITIES ====================
- os.system = {}
- function os.system.shutdown(reboot)
- if reboot then
- computer.shutdown(true)
- else
- computer.shutdown()
- end
- end
- function os.system.uptime()
- return computer.uptime()
- end
- function os.system.freeMemory()
- return computer.freeMemory()
- end
- function os.system.totalMemory()
- return computer.totalMemory()
- end
- function os.system.energy()
- return computer.energy()
- end
- function os.system.maxEnergy()
- return computer.maxEnergy()
- end
- function os.system.sleep(seconds)
- local deadline = computer.uptime() + (seconds or 0)
- repeat
- computer.pullSignal(deadline - computer.uptime())
- until computer.uptime() >= deadline
- end
- function os.system.beep(frequency, duration)
- computer.beep(frequency, duration)
- end
- -- ==================== STRING UTILITIES ====================
- os.string = {}
- function os.string.split(str, sep)
- local parts = {}
- local pattern = string.format("([^%s]+)", sep or " ")
- for part in string.gmatch(str, pattern) do
- table.insert(parts, part)
- end
- return parts
- end
- function os.string.trim(str)
- return string.match(str, "^%s*(.-)%s*$")
- end
- function os.string.startsWith(str, prefix)
- return string.sub(str, 1, #prefix) == prefix
- end
- function os.string.endsWith(str, suffix)
- return string.sub(str, -#suffix) == suffix
- end
- -- ==================== SERIALIZATION ====================
- function os.serialize(value, indent)
- indent = indent or 0
- local t = type(value)
- if t == "number" or t == "boolean" then
- return tostring(value)
- elseif t == "string" then
- return string.format("%q", value)
- elseif t == "table" then
- local parts = {}
- local spaces = string.rep(" ", indent)
- table.insert(parts, "{")
- for k, v in pairs(value) do
- local key
- if type(k) == "string" and k:match("^[%a_][%w_]*$") then
- key = k
- else
- key = "[" .. os.serialize(k) .. "]"
- end
- table.insert(parts, spaces .. " " .. key .. " = " .. os.serialize(v, indent + 1) .. ",")
- end
- table.insert(parts, spaces .. "}")
- return table.concat(parts, "\n")
- else
- return "nil"
- end
- end
- -- ==================== PATH UTILITIES ====================
- os.path = {}
- function os.path.concat(...)
- local parts = {...}
- local result = ""
- for i, part in ipairs(parts) do
- if part ~= "" then
- if result ~= "" and not result:match("/$") then
- result = result .. "/"
- end
- result = result .. part
- end
- end
- return result
- end
- function os.path.split(path)
- local dir, file = path:match("^(.+)/([^/]+)$")
- if not dir then
- return "/", path
- end
- return dir, file
- end
- function os.path.name(path)
- return path:match("[^/]+$") or path
- end
- function os.path.extension(path)
- return path:match("%.([^./]+)$") or ""
- end
- -- Initialize system
- if gpu then
- gpu.set(1, 1, "OS.SYS loaded successfully")
- end
- -- Load saved drive configurations
- os.fs.loadDriveConfig()
- os.tape.loadTapeConfig()
- return true
Advertisement
Add Comment
Please, Sign In to add comment