DorianH935

MDOS command.prg

Dec 23rd, 2025 (edited)
33
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 43.85 KB | None | 0 0
  1. -- COMMAND.PRG - DOS-like command interpreter for Monolith Disk Operating System (M-DOS)
  2.  
  3. local running = true
  4. local currentDir = "/"
  5. local currentDrive = "A"
  6. local historySize = 20
  7. local commandHistory = {}
  8. local historyIndex = 0
  9.  
  10. -- Color codes
  11. local COLOR_WHITE = 0xFFFFFF
  12. local COLOR_GRAY = 0xAAAAAA
  13. local COLOR_YELLOW = 0xFFFF00
  14. local COLOR_RED = 0xFF0000
  15. local COLOR_GREEN = 0x00FF00
  16.  
  17. -- ==================== UTILITY FUNCTIONS ====================
  18. local function print(text)
  19. local w, h = os.display.getResolution()
  20. os.display.write(tostring(text) .. "\n")
  21. end
  22.  
  23. local function clearScreen()
  24. os.display.clear()
  25. os.display.write("", 1, 1)
  26. end
  27.  
  28. local function normalizePath(path)
  29. if not path or path == "" then return currentDir end
  30. if not os.string.startsWith(path, "/") then
  31. path = os.path.concat(currentDir, path)
  32. end
  33.  
  34. -- Normalize path: handle . and ..
  35. path = path:gsub("//+", "/") -- Remove duplicate slashes
  36.  
  37. local parts = {}
  38. for part in path:gmatch("[^/]+") do
  39. if part == ".." then
  40. -- Go up one directory
  41. if #parts > 0 then
  42. table.remove(parts)
  43. end
  44. elseif part ~= "." then
  45. -- Skip "." and add everything else
  46. table.insert(parts, part)
  47. end
  48. end
  49.  
  50. -- Reconstruct path
  51. if #parts == 0 then
  52. return "/"
  53. else
  54. return "/" .. table.concat(parts, "/")
  55. end
  56. end
  57.  
  58. local function formatSize(bytes)
  59. if bytes < 1024 then
  60. return string.format("%d B", bytes)
  61. elseif bytes < 1024 * 1024 then
  62. return string.format("%.1f KB", bytes / 1024)
  63. else
  64. return string.format("%.1f MB", bytes / (1024 * 1024))
  65. end
  66. end
  67.  
  68. local function formatDate(timestamp)
  69. -- Simple date format (timestamp is in seconds)
  70. local days = math.floor(timestamp / 86400)
  71. return string.format("%d days ago", days)
  72. end
  73.  
  74. -- ==================== INPUT HANDLING ====================
  75. local function readLine(prompt)
  76. if prompt then
  77. os.display.write(prompt)
  78. end
  79.  
  80. local line = ""
  81. local cursorPos = 0
  82. local startX = os.display.cursorX
  83. local startY = os.display.cursorY
  84. local historyPos = 0
  85.  
  86. local function drawCursor()
  87. os.display.cursorX = startX + cursorPos
  88. os.display.cursorY = startY
  89. local cursorChar = cursorPos < #line and line:sub(cursorPos + 1, cursorPos + 1) or " "
  90. os.display.setBackground(0xFFFFFF)
  91. os.display.setForeground(0x000000)
  92. os.display.write(cursorChar)
  93. os.display.setBackground(0x000000)
  94. os.display.setForeground(COLOR_WHITE)
  95. end
  96.  
  97. local function redrawLine()
  98. -- Clear the entire line area first
  99. os.display.cursorX = startX
  100. os.display.cursorY = startY
  101. os.display.setBackground(0x000000)
  102. os.display.setForeground(COLOR_WHITE)
  103. local w, _ = os.display.getResolution()
  104. local clearWidth = math.max(0, w - startX + 1)
  105. if clearWidth > 0 then
  106. os.display.write(string.rep(" ", clearWidth))
  107. end
  108.  
  109. -- Redraw the line content
  110. os.display.cursorX = startX
  111. os.display.cursorY = startY
  112. os.display.write(line)
  113.  
  114. -- Draw cursor
  115. drawCursor()
  116. end
  117.  
  118. drawCursor()
  119.  
  120. while true do
  121. local eventType, addr, char, code = os.event.pull(nil, "key_down")
  122.  
  123. if eventType then
  124. -- Enter
  125. if code == os.keyboard.keys.enter then
  126. -- Clear the cursor and redraw the line normally before submitting
  127. os.display.cursorX = startX
  128. os.display.cursorY = startY
  129. os.display.setBackground(0x000000)
  130. os.display.setForeground(COLOR_WHITE)
  131. local w = os.display.getResolution()
  132. os.display.write(string.rep(" ", w - startX + 1))
  133. os.display.cursorX = startX
  134. os.display.cursorY = startY
  135. os.display.write(line)
  136. os.display.write("\n")
  137. return line
  138. -- Backspace
  139. elseif code == os.keyboard.keys.back then
  140. if cursorPos > 0 then
  141. line = line:sub(1, cursorPos - 1) .. line:sub(cursorPos + 1)
  142. cursorPos = cursorPos - 1
  143. redrawLine()
  144. end
  145. -- Up arrow - previous command
  146. elseif code == os.keyboard.keys.up then
  147. if historyPos < #commandHistory then
  148. historyPos = historyPos + 1
  149. line = commandHistory[#commandHistory - historyPos + 1] or ""
  150. cursorPos = #line
  151. redrawLine()
  152. end
  153. -- Down arrow - next command
  154. elseif code == os.keyboard.keys.down then
  155. if historyPos > 0 then
  156. historyPos = historyPos - 1
  157. if historyPos == 0 then
  158. line = ""
  159. else
  160. line = commandHistory[#commandHistory - historyPos + 1] or ""
  161. end
  162. cursorPos = #line
  163. redrawLine()
  164. end
  165. -- Left arrow
  166. elseif code == os.keyboard.keys.left then
  167. if cursorPos > 0 then
  168. -- Redraw old cursor position
  169. os.display.cursorX = startX + cursorPos
  170. os.display.cursorY = startY
  171. os.display.setBackground(0x000000)
  172. os.display.setForeground(COLOR_WHITE)
  173. os.display.write(cursorPos <= #line and line:sub(cursorPos, cursorPos) or " ")
  174.  
  175. cursorPos = cursorPos - 1
  176. drawCursor()
  177. end
  178. -- Right arrow
  179. elseif code == os.keyboard.keys.right then
  180. if cursorPos < #line then
  181. -- Redraw old cursor position
  182. os.display.cursorX = startX + cursorPos
  183. os.display.cursorY = startY
  184. os.display.setBackground(0x000000)
  185. os.display.setForeground(COLOR_WHITE)
  186. os.display.write(line:sub(cursorPos + 1, cursorPos + 1))
  187.  
  188. cursorPos = cursorPos + 1
  189. drawCursor()
  190. end
  191. -- Home
  192. elseif code == os.keyboard.keys.home then
  193. if cursorPos < #line then
  194. os.display.cursorX = startX + cursorPos
  195. os.display.cursorY = startY
  196. os.display.setBackground(0x000000)
  197. os.display.setForeground(COLOR_WHITE)
  198. os.display.write(line:sub(cursorPos + 1, cursorPos + 1))
  199. end
  200. cursorPos = 0
  201. drawCursor()
  202. -- End
  203. elseif code == os.keyboard.keys["end"] then
  204. if cursorPos < #line then
  205. os.display.cursorX = startX + cursorPos
  206. os.display.cursorY = startY
  207. os.display.setBackground(0x000000)
  208. os.display.setForeground(COLOR_WHITE)
  209. os.display.write(line:sub(cursorPos + 1, cursorPos + 1))
  210. end
  211. cursorPos = #line
  212. drawCursor()
  213. -- Regular character
  214. elseif char > 0 and char < 256 and not os.keyboard.isControl(char) then
  215. line = line:sub(1, cursorPos) .. string.char(char) .. line:sub(cursorPos + 1)
  216. cursorPos = cursorPos + 1
  217. redrawLine()
  218. end
  219. end
  220. end
  221. end
  222.  
  223. -- ==================== BUILT-IN COMMANDS ====================
  224. local commands = {}
  225.  
  226. commands.help = function(args)
  227. -- Check if asking for help on a specific program
  228. if args[1] then
  229. local programPath = normalizePath(args[1])
  230.  
  231. -- Add .PRG extension if not present
  232. if not os.string.endsWith(programPath:lower(), ".prg") then
  233. programPath = programPath .. ".PRG"
  234. end
  235.  
  236. if not os.fs.exists(programPath) then
  237. os.display.setForeground(COLOR_RED)
  238. print("Program not found: " .. programPath)
  239. os.display.setForeground(COLOR_WHITE)
  240. return
  241. end
  242.  
  243. -- Read the program file
  244. local code = os.fs.readAll(programPath)
  245. if not code then
  246. os.display.setForeground(COLOR_RED)
  247. print("Failed to read program")
  248. os.display.setForeground(COLOR_WHITE)
  249. return
  250. end
  251.  
  252. -- Look for help text in comments at the start of the file
  253. -- Format: -- HELP: description here
  254. local helpText = nil
  255. for line in code:gmatch("[^\r\n]+") do
  256. if line:match("^%s*%-%-HELP:%s*(.+)") then
  257. helpText = line:match("^%s*%-%-HELP:%s*(.+)")
  258. break
  259. end
  260. -- Stop at first non-comment line
  261. if not line:match("^%s*%-%-") and line:match("%S") then
  262. break
  263. end
  264. end
  265.  
  266. if helpText then
  267. os.display.setForeground(COLOR_YELLOW)
  268. print("Help for " .. args[1] .. ":")
  269. os.display.setForeground(COLOR_WHITE)
  270. print(helpText)
  271. else
  272. os.display.setForeground(COLOR_YELLOW)
  273. print("No help available for " .. args[1])
  274. os.display.setForeground(COLOR_WHITE)
  275. end
  276. return
  277. end
  278.  
  279. -- Show general help
  280. os.display.setForeground(COLOR_YELLOW)
  281. print("Available commands:")
  282. os.display.setForeground(COLOR_WHITE)
  283. print(" DIR [path] - List directory contents")
  284. print(" CD <path> - Change directory")
  285. print(" TYPE <file> - Display file contents")
  286. print(" DEL <file> - Delete a file")
  287. print(" COPY <src> <dst> - Copy a file")
  288. print(" REN <old> <new> - Rename a file")
  289. print(" MD <path> - Make directory")
  290. print(" RD <path> - Remove directory")
  291. print(" CLS - Clear screen")
  292. print(" MEM - Show memory info")
  293. print(" POWER - Show power info")
  294. print(" TIME - Show system uptime")
  295. print(" RUN <file> - Run a .PRG file")
  296. print(" EDIT <file> - Simple file editor (Ctrl+S save, Ctrl+X exit)")
  297. print(" SYS <drive> - Copy system files to drive")
  298. print(" FORMAT <drive> - Format a tape drive")
  299. print(" FDISK - Manage disk drives")
  300. print(" FTAPE - Manage tape drives")
  301. print(" REBOOT - Reboot computer")
  302. print(" SHUTDOWN - Shutdown computer")
  303. print(" HELP [program] - Show this help or help for a program")
  304. print(" EXIT - Exit to BIOS")
  305. print("")
  306. print("Use HELP <program.prg> to see help for a specific program")
  307. end
  308.  
  309. commands.dir = function(args)
  310. local path = normalizePath(args[1])
  311.  
  312. if not os.fs.exists(path) then
  313. os.display.setForeground(COLOR_RED)
  314. print("Directory not found: " .. path)
  315. os.display.setForeground(COLOR_WHITE)
  316. return
  317. end
  318.  
  319. if not os.fs.isDirectory(path) then
  320. os.display.setForeground(COLOR_RED)
  321. print("Not a directory: " .. path)
  322. os.display.setForeground(COLOR_WHITE)
  323. return
  324. end
  325.  
  326. local entries = os.fs.list(path)
  327. if not entries then
  328. os.display.setForeground(COLOR_RED)
  329. print("Failed to list directory")
  330. os.display.setForeground(COLOR_WHITE)
  331. return
  332. end
  333.  
  334. print("\nDirectory of " .. path)
  335. print("")
  336.  
  337. local fileCount = 0
  338. local dirCount = 0
  339. local totalSize = 0
  340.  
  341. for _, entry in ipairs(entries) do
  342. local fullPath = os.path.concat(path, entry)
  343. local isDir = os.fs.isDirectory(fullPath)
  344. local size = isDir and 0 or (os.fs.size(fullPath) or 0)
  345.  
  346. if isDir then
  347. os.display.setForeground(COLOR_YELLOW)
  348. print(string.format("%-30s <DIR>", entry))
  349. dirCount = dirCount + 1
  350. else
  351. os.display.setForeground(COLOR_WHITE)
  352. print(string.format("%-30s %10s", entry, formatSize(size)))
  353. fileCount = fileCount + 1
  354. totalSize = totalSize + size
  355. end
  356. end
  357.  
  358. os.display.setForeground(COLOR_GRAY)
  359. print(string.format("\n%d File(s) %s", fileCount, formatSize(totalSize)))
  360. print(string.format("%d Dir(s)", dirCount))
  361. os.display.setForeground(COLOR_WHITE)
  362. end
  363.  
  364. commands.cd = function(args)
  365. if not args[1] then
  366. print(currentDir)
  367. return
  368. end
  369.  
  370. local path = normalizePath(args[1])
  371.  
  372. if not os.fs.exists(path) then
  373. os.display.setForeground(COLOR_RED)
  374. print("Directory not found")
  375. os.display.setForeground(COLOR_WHITE)
  376. return
  377. end
  378.  
  379. if not os.fs.isDirectory(path) then
  380. os.display.setForeground(COLOR_RED)
  381. print("Not a directory")
  382. os.display.setForeground(COLOR_WHITE)
  383. return
  384. end
  385.  
  386. currentDir = path
  387. end
  388.  
  389. commands.type = function(args)
  390. if not args[1] then
  391. print("Usage: TYPE <file>")
  392. return
  393. end
  394.  
  395. local path = normalizePath(args[1])
  396.  
  397. if not os.fs.exists(path) then
  398. os.display.setForeground(COLOR_RED)
  399. print("File not found")
  400. os.display.setForeground(COLOR_WHITE)
  401. return
  402. end
  403.  
  404. local content = os.fs.readAll(path)
  405. if content then
  406. print(content)
  407. else
  408. os.display.setForeground(COLOR_RED)
  409. print("Failed to read file")
  410. os.display.setForeground(COLOR_WHITE)
  411. end
  412. end
  413.  
  414. commands.del = function(args)
  415. if not args[1] then
  416. print("Usage: DEL <file>")
  417. return
  418. end
  419.  
  420. local path = normalizePath(args[1])
  421.  
  422. if not os.fs.exists(path) then
  423. os.display.setForeground(COLOR_RED)
  424. print("File not found")
  425. os.display.setForeground(COLOR_WHITE)
  426. return
  427. end
  428.  
  429. local ok, err = os.fs.remove(path)
  430. if ok then
  431. os.display.setForeground(COLOR_GREEN)
  432. print("Deleted: " .. path)
  433. os.display.setForeground(COLOR_WHITE)
  434. else
  435. os.display.setForeground(COLOR_RED)
  436. print("Failed to delete: " .. tostring(err))
  437. os.display.setForeground(COLOR_WHITE)
  438. end
  439. end
  440.  
  441. commands.copy = function(args)
  442. if not args[1] or not args[2] then
  443. print("Usage: COPY <source> <destination>")
  444. return
  445. end
  446.  
  447. local src = normalizePath(args[1])
  448. local dst = normalizePath(args[2])
  449.  
  450. -- Handle cross-drive copying
  451. local srcDrive = currentDrive
  452. local dstDrive = currentDrive
  453.  
  454. -- Parse source drive if specified
  455. if args[1]:match("^[A-Za-z]:") then
  456. srcDrive = args[1]:sub(1, 1):upper()
  457. src = args[1]:sub(3)
  458. if not src:match("^/") then
  459. src = "/" .. src
  460. end
  461. end
  462.  
  463. -- Parse destination drive if specified
  464. if args[2]:match("^[A-Za-z]:") then
  465. dstDrive = args[2]:sub(1, 1):upper()
  466. dst = args[2]:sub(3)
  467. if not dst:match("^/") then
  468. dst = "/" .. dst
  469. end
  470. end
  471.  
  472. -- Get source and destination proxies
  473. local srcProxy = os.fs.drives[srcDrive]
  474. local dstProxy = os.fs.drives[dstDrive]
  475.  
  476. if not srcProxy then
  477. os.display.setForeground(COLOR_RED)
  478. print("Source drive not found: " .. srcDrive .. ":")
  479. os.display.setForeground(COLOR_WHITE)
  480. return
  481. end
  482.  
  483. if not dstProxy then
  484. os.display.setForeground(COLOR_RED)
  485. print("Destination drive not found: " .. dstDrive .. ":")
  486. os.display.setForeground(COLOR_WHITE)
  487. return
  488. end
  489.  
  490. -- Check if source exists
  491. if not srcProxy.exists(src) then
  492. os.display.setForeground(COLOR_RED)
  493. print("Source file not found: " .. srcDrive .. ":" .. src)
  494. os.display.setForeground(COLOR_WHITE)
  495. return
  496. end
  497.  
  498. -- If destination is a directory, append source filename
  499. if dstProxy.exists(dst) and dstProxy.isDirectory(dst) then
  500. local filename = os.path.name(src)
  501. dst = os.path.concat(dst, filename)
  502. end
  503.  
  504. -- Read from source
  505. local handle = srcProxy.open(src, "r")
  506. if not handle then
  507. os.display.setForeground(COLOR_RED)
  508. print("Failed to read source file")
  509. os.display.setForeground(COLOR_WHITE)
  510. return
  511. end
  512.  
  513. local content = ""
  514. repeat
  515. local chunk = srcProxy.read(handle, math.huge)
  516. content = content .. (chunk or "")
  517. until not chunk
  518. srcProxy.close(handle)
  519.  
  520. -- Write to destination
  521. local dstHandle = dstProxy.open(dst, "w")
  522. if not dstHandle then
  523. os.display.setForeground(COLOR_RED)
  524. print("Failed to write destination file")
  525. os.display.setForeground(COLOR_WHITE)
  526. return
  527. end
  528.  
  529. dstProxy.write(dstHandle, content)
  530. dstProxy.close(dstHandle)
  531.  
  532. os.display.setForeground(COLOR_GREEN)
  533. print("Copied: " .. srcDrive .. ":" .. src .. " -> " .. dstDrive .. ":" .. dst)
  534. os.display.setForeground(COLOR_WHITE)
  535. end
  536.  
  537. commands.ren = function(args)
  538. if not args[1] or not args[2] then
  539. print("Usage: REN <oldname> <newname>")
  540. return
  541. end
  542.  
  543. local src = normalizePath(args[1])
  544. local dst = normalizePath(args[2])
  545.  
  546. local ok, err = os.fs.rename(src, dst)
  547. if ok then
  548. os.display.setForeground(COLOR_GREEN)
  549. print("Renamed: " .. src .. " -> " .. dst)
  550. os.display.setForeground(COLOR_WHITE)
  551. else
  552. os.display.setForeground(COLOR_RED)
  553. print("Failed to rename: " .. tostring(err))
  554. os.display.setForeground(COLOR_WHITE)
  555. end
  556. end
  557.  
  558. commands.md = function(args)
  559. if not args[1] then
  560. print("Usage: MD <directory>")
  561. return
  562. end
  563.  
  564. local path = normalizePath(args[1])
  565. local ok, err = os.fs.makeDirectory(path)
  566. if ok then
  567. os.display.setForeground(COLOR_GREEN)
  568. print("Created directory: " .. path)
  569. os.display.setForeground(COLOR_WHITE)
  570. else
  571. os.display.setForeground(COLOR_RED)
  572. print("Failed to create directory: " .. tostring(err))
  573. os.display.setForeground(COLOR_WHITE)
  574. end
  575. end
  576.  
  577. commands.rd = function(args)
  578. if not args[1] then
  579. print("Usage: RD <directory>")
  580. return
  581. end
  582.  
  583. local path = normalizePath(args[1])
  584. local ok, err = os.fs.remove(path)
  585. if ok then
  586. os.display.setForeground(COLOR_GREEN)
  587. print("Removed directory: " .. path)
  588. os.display.setForeground(COLOR_WHITE)
  589. else
  590. os.display.setForeground(COLOR_RED)
  591. print("Failed to remove directory: " .. tostring(err))
  592. os.display.setForeground(COLOR_WHITE)
  593. end
  594. end
  595.  
  596. commands.cls = function(args)
  597. clearScreen()
  598. end
  599.  
  600. commands.mem = function(args)
  601. local free = os.system.freeMemory()
  602. local total = os.system.totalMemory()
  603. local used = total - free
  604.  
  605. os.display.setForeground(COLOR_YELLOW)
  606. print("Memory Information:")
  607. os.display.setForeground(COLOR_WHITE)
  608. print(string.format(" Total: %s", formatSize(total)))
  609. print(string.format(" Used: %s (%.1f%%)", formatSize(used), (used / total) * 100))
  610. print(string.format(" Free: %s (%.1f%%)", formatSize(free), (free / total) * 100))
  611. end
  612.  
  613. commands.power = function(args)
  614. local energy = os.system.energy()
  615. local maxEnergy = os.system.maxEnergy()
  616.  
  617. os.display.setForeground(COLOR_YELLOW)
  618. print("Power Information:")
  619. os.display.setForeground(COLOR_WHITE)
  620. print(string.format(" Current: %.0f / %.0f", energy, maxEnergy))
  621. print(string.format(" Percent: %.1f%%", (energy / maxEnergy) * 100))
  622. end
  623.  
  624. commands.time = function(args)
  625. local uptime = os.system.uptime()
  626. local hours = math.floor(uptime / 3600)
  627. local minutes = math.floor((uptime % 3600) / 60)
  628. local seconds = math.floor(uptime % 60)
  629.  
  630. print(string.format("System uptime: %02d:%02d:%02d", hours, minutes, seconds))
  631. end
  632.  
  633. commands.run = function(args)
  634. if not args[1] then
  635. print("Usage: RUN <file>")
  636. return
  637. end
  638.  
  639. local path = normalizePath(args[1])
  640.  
  641. if not os.fs.exists(path) then
  642. os.display.setForeground(COLOR_RED)
  643. print("File not found")
  644. os.display.setForeground(COLOR_WHITE)
  645. return
  646. end
  647.  
  648. local code = os.fs.readAll(path)
  649. if not code then
  650. os.display.setForeground(COLOR_RED)
  651. print("Failed to read file")
  652. os.display.setForeground(COLOR_WHITE)
  653. return
  654. end
  655.  
  656. local func, err = load(code, "=" .. path, "t", _G)
  657. if not func then
  658. os.display.setForeground(COLOR_RED)
  659. print("Syntax error: " .. tostring(err))
  660. os.display.setForeground(COLOR_WHITE)
  661. return
  662. end
  663.  
  664. local ok, result = pcall(func)
  665. if not ok then
  666. os.display.setForeground(COLOR_RED)
  667. print("Runtime error: " .. tostring(result))
  668. os.display.setForeground(COLOR_WHITE)
  669. end
  670. end
  671.  
  672. commands.edit = function(args)
  673. if not args[1] then
  674. print("Usage: EDIT <file>")
  675. return
  676. end
  677.  
  678. local path = normalizePath(args[1])
  679. local content = ""
  680. local lines = {}
  681.  
  682. if os.fs.exists(path) then
  683. content = os.fs.readAll(path) or ""
  684. for line in content:gmatch("[^\r\n]*") do
  685. table.insert(lines, line)
  686. end
  687. end
  688.  
  689. -- If file is empty, start with one empty line
  690. if #lines == 0 then
  691. table.insert(lines, "")
  692. end
  693.  
  694. local w, h = os.display.getResolution()
  695. local currentLine = 1
  696. local scrollOffset = 0
  697. local modified = false
  698. local statusHeight = 2
  699. local editHeight = h - statusHeight
  700.  
  701. local function redraw()
  702. clearScreen()
  703.  
  704. -- Draw file content
  705. for i = 1, editHeight do
  706. local lineNum = i + scrollOffset
  707. if lineNum <= #lines then
  708. os.display.cursorY = i
  709. os.display.cursorX = 1
  710.  
  711. -- Line number
  712. os.display.setForeground(COLOR_GRAY)
  713. os.display.write(string.format("%3d ", lineNum))
  714.  
  715. -- Line content
  716. os.display.setForeground(COLOR_WHITE)
  717. local lineText = lines[lineNum] or ""
  718. if #lineText > w - 5 then
  719. lineText = lineText:sub(1, w - 5)
  720. end
  721. os.display.write(lineText)
  722. end
  723. end
  724.  
  725. -- Draw status bar
  726. os.display.cursorY = h - 1
  727. os.display.cursorX = 1
  728. os.display.setBackground(0x444444)
  729. os.display.setForeground(COLOR_WHITE)
  730. local status = string.format(" %s %s Line %d/%d", path, modified and "[Modified]" or "", currentLine, #lines)
  731. os.display.write(status .. string.rep(" ", w - #status))
  732.  
  733. -- Draw help bar
  734. os.display.cursorY = h
  735. os.display.cursorX = 1
  736. local help = " Ctrl+S: Save Ctrl+X: Exit Arrows: Navigate"
  737. os.display.write(help .. string.rep(" ", w - #help))
  738. os.display.setBackground(0x000000)
  739. os.display.setForeground(COLOR_WHITE)
  740.  
  741. -- Position cursor on current line
  742. local displayLine = currentLine - scrollOffset
  743. if displayLine < 1 then
  744. scrollOffset = currentLine - 1
  745. redraw()
  746. return
  747. elseif displayLine > editHeight then
  748. scrollOffset = currentLine - editHeight
  749. redraw()
  750. return
  751. end
  752.  
  753. os.display.cursorY = displayLine
  754. os.display.cursorX = 5 + #(lines[currentLine] or "")
  755. end
  756.  
  757. local function editLine(lineNum)
  758. local displayLine = lineNum - scrollOffset
  759. os.display.cursorY = displayLine
  760. os.display.cursorX = 5
  761.  
  762. local line = lines[lineNum] or ""
  763. os.display.setForeground(COLOR_WHITE)
  764. os.display.write(line .. string.rep(" ", w - 5 - #line))
  765.  
  766. local cursorPos = #line
  767.  
  768. -- Draw cursor
  769. local function drawCursor()
  770. os.display.cursorX = 5 + cursorPos
  771. os.display.cursorY = displayLine
  772. local cursorChar = cursorPos < #line and line:sub(cursorPos + 1, cursorPos + 1) or " "
  773. os.display.setBackground(0xFFFFFF)
  774. os.display.setForeground(0x000000)
  775. os.display.write(cursorChar)
  776. os.display.setBackground(0x000000)
  777. os.display.setForeground(COLOR_WHITE)
  778. end
  779.  
  780. drawCursor()
  781.  
  782. while true do
  783. local eventType, addr, char, code = os.event.pull()
  784.  
  785. if eventType == "key_down" then
  786. -- Ctrl+S - Save
  787. if code == os.keyboard.keys.s and os.keyboard.isControlDown() then
  788. lines[lineNum] = line -- Save current line first
  789. local newContent = table.concat(lines, "\n")
  790. local ok, err = os.fs.writeAll(path, newContent)
  791. if ok then
  792. modified = false
  793. redraw()
  794. -- Show save confirmation briefly
  795. os.display.cursorY = h - 1
  796. os.display.cursorX = 1
  797. os.display.setBackground(0x00FF00)
  798. os.display.setForeground(0x000000)
  799. os.display.write(" Saved! " .. string.rep(" ", w - 8))
  800. os.system.sleep(0.5)
  801. redraw()
  802. drawCursor()
  803. else
  804. -- Show error briefly
  805. os.display.cursorY = h - 1
  806. os.display.cursorX = 1
  807. os.display.setBackground(0xFF0000)
  808. os.display.write(" Error: " .. tostring(err) .. string.rep(" ", w - 8 - #tostring(err)))
  809. os.system.sleep(2)
  810. redraw()
  811. drawCursor()
  812. end
  813. -- Ctrl+X - Exit
  814. elseif code == os.keyboard.keys.x and os.keyboard.isControlDown() then
  815. lines[lineNum] = line -- Save current line
  816. return "exit"
  817. -- Arrow keys
  818. elseif code == os.keyboard.keys.up then
  819. lines[lineNum] = line
  820. if os.keyboard.isShiftDown() then
  821. -- Shift+Up: scroll view up
  822. if scrollOffset > 0 then
  823. scrollOffset = scrollOffset - 1
  824. redraw()
  825. end
  826. drawCursor()
  827. else
  828. -- Normal up: move to previous line
  829. return "up"
  830. end
  831. elseif code == os.keyboard.keys.down then
  832. lines[lineNum] = line
  833. if os.keyboard.isShiftDown() then
  834. -- Shift+Down: scroll view down
  835. if scrollOffset < #lines - editHeight then
  836. scrollOffset = scrollOffset + 1
  837. redraw()
  838. end
  839. drawCursor()
  840. else
  841. -- Normal down: move to next line
  842. return "down"
  843. end
  844. elseif code == os.keyboard.keys.left then
  845. if cursorPos > 0 then
  846. -- Redraw character at old cursor position
  847. os.display.cursorX = 5 + cursorPos
  848. os.display.cursorY = displayLine
  849. os.display.setBackground(0x000000)
  850. os.display.setForeground(COLOR_WHITE)
  851. os.display.write(cursorPos <= #line and line:sub(cursorPos, cursorPos) or " ")
  852.  
  853. cursorPos = cursorPos - 1
  854. drawCursor()
  855. end
  856. elseif code == os.keyboard.keys.right then
  857. if cursorPos < #line then
  858. -- Redraw character at old cursor position
  859. os.display.cursorX = 5 + cursorPos
  860. os.display.cursorY = displayLine
  861. os.display.setBackground(0x000000)
  862. os.display.setForeground(COLOR_WHITE)
  863. os.display.write(line:sub(cursorPos + 1, cursorPos + 1))
  864.  
  865. cursorPos = cursorPos + 1
  866. drawCursor()
  867. end
  868. elseif code == os.keyboard.keys.home then
  869. -- Redraw old cursor position
  870. if cursorPos < #line then
  871. os.display.cursorX = 5 + cursorPos
  872. os.display.cursorY = displayLine
  873. os.display.setBackground(0x000000)
  874. os.display.setForeground(COLOR_WHITE)
  875. os.display.write(line:sub(cursorPos + 1, cursorPos + 1))
  876. end
  877.  
  878. cursorPos = 0
  879. drawCursor()
  880. elseif code == os.keyboard.keys["end"] then
  881. -- Redraw old cursor position
  882. if cursorPos < #line then
  883. os.display.cursorX = 5 + cursorPos
  884. os.display.cursorY = displayLine
  885. os.display.setBackground(0x000000)
  886. os.display.setForeground(COLOR_WHITE)
  887. os.display.write(line:sub(cursorPos + 1, cursorPos + 1))
  888. end
  889.  
  890. cursorPos = #line
  891. drawCursor()
  892. -- Enter - Next line
  893. elseif code == os.keyboard.keys.enter then
  894. lines[lineNum] = line
  895. modified = true
  896. return "next"
  897. -- Backspace
  898. elseif code == os.keyboard.keys.back then
  899. if cursorPos > 0 then
  900. line = line:sub(1, cursorPos - 1) .. line:sub(cursorPos + 1)
  901. cursorPos = cursorPos - 1
  902. os.display.cursorX = 5
  903. os.display.cursorY = displayLine
  904. os.display.setBackground(0x000000)
  905. os.display.setForeground(COLOR_WHITE)
  906. os.display.write(line .. " ")
  907. modified = true
  908. drawCursor()
  909. elseif lineNum > 1 then
  910. -- Merge with previous line
  911. local prevLine = lines[lineNum - 1]
  912. lines[lineNum - 1] = prevLine .. line
  913. table.remove(lines, lineNum)
  914. modified = true
  915. return "prev"
  916. end
  917. -- Regular character
  918. elseif char > 0 and not os.keyboard.isControl(char) then
  919. if #line < w - 6 then
  920. line = line:sub(1, cursorPos) .. string.char(char) .. line:sub(cursorPos + 1)
  921. cursorPos = cursorPos + 1
  922. os.display.cursorX = 5
  923. os.display.cursorY = displayLine
  924. os.display.setBackground(0x000000)
  925. os.display.setForeground(COLOR_WHITE)
  926. os.display.write(line)
  927. modified = true
  928. drawCursor()
  929. end
  930. end
  931. end
  932. end
  933. end
  934.  
  935. redraw()
  936.  
  937. while true do
  938. local result = editLine(currentLine)
  939.  
  940. if result == "exit" then
  941. if modified then
  942. os.display.cursorY = h - 1
  943. os.display.cursorX = 1
  944. os.display.setBackground(0x444444)
  945. os.display.write(" Save changes? (Y/N) " .. string.rep(" ", w - 21))
  946. os.display.setBackground(0x000000)
  947.  
  948. local answer = ""
  949. while true do
  950. local eventType, addr, char, code = os.event.pull(nil, "key_down")
  951. if char > 0 then
  952. answer = string.char(char):upper()
  953. break
  954. end
  955. end
  956.  
  957. if answer == "Y" then
  958. local newContent = table.concat(lines, "\n")
  959. os.fs.writeAll(path, newContent)
  960. end
  961. end
  962. clearScreen()
  963. return
  964. elseif result == "next" then
  965. if currentLine < #lines then
  966. currentLine = currentLine + 1
  967. else
  968. table.insert(lines, "")
  969. currentLine = #lines
  970. end
  971. redraw()
  972. elseif result == "up" then
  973. if currentLine > 1 then
  974. currentLine = currentLine - 1
  975. end
  976. redraw()
  977. elseif result == "down" then
  978. if currentLine < #lines then
  979. currentLine = currentLine + 1
  980. else
  981. table.insert(lines, "")
  982. currentLine = #lines
  983. end
  984. redraw()
  985. elseif result == "prev" then
  986. if currentLine > 1 then
  987. currentLine = currentLine - 1
  988. end
  989. redraw()
  990. end
  991. end
  992. end
  993.  
  994. commands.reboot = function(args)
  995. print("Rebooting...")
  996. os.system.sleep(1)
  997. os.system.shutdown(true)
  998. end
  999.  
  1000. commands.shutdown = function(args)
  1001. print("Shutting down...")
  1002. os.system.sleep(1)
  1003. os.system.shutdown(false)
  1004. end
  1005.  
  1006. commands.exit = function(args)
  1007. running = false
  1008. end
  1009.  
  1010. commands.sys = function(args)
  1011. if not args[1] then
  1012. print("Usage: SYS <drive>")
  1013. print("Example: SYS B:")
  1014. return
  1015. end
  1016.  
  1017. local letter = args[1]:upper()
  1018. if not letter:match("^[A-Z]:$") then
  1019. os.display.setForeground(COLOR_RED)
  1020. print("Invalid drive format. Use format like: B:")
  1021. os.display.setForeground(COLOR_WHITE)
  1022. return
  1023. end
  1024.  
  1025. letter = letter:sub(1, 1)
  1026. local targetDrive = os.fs.getDrive(letter)
  1027.  
  1028. if not targetDrive then
  1029. os.display.setForeground(COLOR_RED)
  1030. print("Drive " .. letter .. ": not found")
  1031. os.display.setForeground(COLOR_WHITE)
  1032. return
  1033. end
  1034.  
  1035. if letter == "A" then
  1036. os.display.setForeground(COLOR_RED)
  1037. print("Cannot copy system to boot drive")
  1038. os.display.setForeground(COLOR_WHITE)
  1039. return
  1040. end
  1041.  
  1042. -- Check if it's a tape drive
  1043. if targetDrive.type == "tapefs" then
  1044. os.display.setForeground(COLOR_RED)
  1045. print("Cannot make tape drives bootable")
  1046. os.display.setForeground(COLOR_WHITE)
  1047. return
  1048. end
  1049.  
  1050. os.display.setForeground(COLOR_YELLOW)
  1051. print("Copying system files to " .. letter .. ":...")
  1052. os.display.setForeground(COLOR_WHITE)
  1053.  
  1054. -- Get boot drive
  1055. local bootDrive = os.fs.drives["A"]
  1056.  
  1057. -- Copy init.lua
  1058. local files = {"init.lua", "OS.SYS", "COMMAND.PRG"}
  1059. local success = true
  1060.  
  1061. for _, filename in ipairs(files) do
  1062. print(" Copying " .. filename .. "...")
  1063.  
  1064. -- Read from boot drive
  1065. local handle = bootDrive.open(filename, "r")
  1066. if not handle then
  1067. os.display.setForeground(COLOR_RED)
  1068. print(" Failed to read " .. filename)
  1069. os.display.setForeground(COLOR_WHITE)
  1070. success = false
  1071. break
  1072. end
  1073.  
  1074. local content = ""
  1075. repeat
  1076. local chunk = bootDrive.read(handle, math.huge)
  1077. content = content .. (chunk or "")
  1078. until not chunk
  1079. bootDrive.close(handle)
  1080.  
  1081. -- Write to target drive
  1082. local targetHandle = targetDrive.open(filename, "w")
  1083. if not targetHandle then
  1084. os.display.setForeground(COLOR_RED)
  1085. print(" Failed to write " .. filename)
  1086. os.display.setForeground(COLOR_WHITE)
  1087. success = false
  1088. break
  1089. end
  1090.  
  1091. targetDrive.write(targetHandle, content)
  1092. targetDrive.close(targetHandle)
  1093. end
  1094.  
  1095. if success then
  1096. os.display.setForeground(COLOR_GREEN)
  1097. print("System files copied successfully!")
  1098. print("Drive " .. letter .. ": is now bootable")
  1099. os.display.setForeground(COLOR_WHITE)
  1100. end
  1101. end
  1102.  
  1103. commands.format = function(args)
  1104. if not args[1] then
  1105. print("Usage: FORMAT <drive>")
  1106. print("Example: FORMAT C:")
  1107. return
  1108. end
  1109.  
  1110. local letter = args[1]:upper()
  1111. if not letter:match("^[A-Z]:$") then
  1112. os.display.setForeground(COLOR_RED)
  1113. print("Invalid drive format. Use format like: C:")
  1114. os.display.setForeground(COLOR_WHITE)
  1115. return
  1116. end
  1117.  
  1118. letter = letter:sub(1, 1)
  1119.  
  1120. -- Check if it's a tape
  1121. local tapeProxy = os.tape.tapes[letter]
  1122. if not tapeProxy then
  1123. os.display.setForeground(COLOR_RED)
  1124. print("Drive " .. letter .. ": is not a tape drive")
  1125. print("Use FTAPE to assign tape drives first")
  1126. os.display.setForeground(COLOR_WHITE)
  1127. return
  1128. end
  1129.  
  1130. os.display.setForeground(COLOR_YELLOW)
  1131. print("WARNING: This will erase all data on tape " .. letter .. ":")
  1132. os.display.setForeground(COLOR_WHITE)
  1133. print("Are you sure? (Y/N)")
  1134. local answer = readLine("> "):upper()
  1135.  
  1136. if answer ~= "Y" then
  1137. print("Format cancelled")
  1138. return
  1139. end
  1140.  
  1141. print("Formatting tape " .. letter .. ":...")
  1142. local ok, err = os.tape.formatTape(tapeProxy)
  1143.  
  1144. if ok then
  1145. os.display.setForeground(COLOR_GREEN)
  1146. print("Tape formatted successfully!")
  1147. print("Drive " .. letter .. ": is now ready to use")
  1148. os.display.setForeground(COLOR_WHITE)
  1149. else
  1150. os.display.setForeground(COLOR_RED)
  1151. print("Format failed: " .. tostring(err))
  1152. os.display.setForeground(COLOR_WHITE)
  1153. end
  1154. end
  1155.  
  1156. commands.fdisk = function(args)
  1157. os.display.setForeground(COLOR_YELLOW)
  1158. print("Fixed Disk Manager")
  1159. print("==================")
  1160. os.display.setForeground(COLOR_WHITE)
  1161. print("")
  1162.  
  1163. -- List current drive assignments
  1164. print("Current drive assignments:")
  1165. local drives = os.fs.listDrives()
  1166. if #drives == 0 then
  1167. print(" (none)")
  1168. else
  1169. for _, drive in ipairs(drives) do
  1170. print(string.format(" %s: %s", drive.letter, drive.address:sub(1, 8)))
  1171. end
  1172. end
  1173. print("")
  1174.  
  1175. -- List available filesystems (excluding tmpfs)
  1176. print("Available filesystems:")
  1177. local component = component
  1178. local tmpAddr = computer.tmpAddress()
  1179. local fsIndex = 1
  1180. local filesystems = {}
  1181. for addr, ctype in component.list("filesystem", true) do
  1182. if addr ~= tmpAddr then
  1183. print(string.format(" %d. %s (%s)", fsIndex, addr:sub(1, 8), ctype))
  1184. filesystems[fsIndex] = addr
  1185. fsIndex = fsIndex + 1
  1186. end
  1187. end
  1188.  
  1189. if fsIndex == 1 then
  1190. print(" (none available)")
  1191. return
  1192. end
  1193.  
  1194. print("")
  1195. print("Enter number to assign (or 0 to cancel):")
  1196. local choice = readLine("> ")
  1197. choice = tonumber(choice)
  1198.  
  1199. if not choice or choice == 0 then
  1200. print("Cancelled")
  1201. return
  1202. end
  1203.  
  1204. if not filesystems[choice] then
  1205. os.display.setForeground(COLOR_RED)
  1206. print("Invalid choice")
  1207. os.display.setForeground(COLOR_WHITE)
  1208. return
  1209. end
  1210.  
  1211. print("Enter drive letter (A-Z):")
  1212. local letter = readLine("> ")
  1213. letter = os.string.trim(letter):upper()
  1214.  
  1215. if #letter ~= 1 or letter < "A" or letter > "Z" then
  1216. os.display.setForeground(COLOR_RED)
  1217. print("Invalid drive letter")
  1218. os.display.setForeground(COLOR_WHITE)
  1219. return
  1220. end
  1221.  
  1222. local ok, err = os.fs.setDrive(letter, filesystems[choice])
  1223. if ok then
  1224. os.display.setForeground(COLOR_GREEN)
  1225. print(string.format("Drive %s: assigned to %s", letter, filesystems[choice]:sub(1, 8)))
  1226. os.display.setForeground(COLOR_WHITE)
  1227. else
  1228. os.display.setForeground(COLOR_RED)
  1229. print("Failed to assign drive: " .. tostring(err))
  1230. os.display.setForeground(COLOR_WHITE)
  1231. end
  1232. end
  1233.  
  1234. commands.ftape = function(args)
  1235. os.display.setForeground(COLOR_YELLOW)
  1236. print("Tape Drive Manager")
  1237. print("==================")
  1238. os.display.setForeground(COLOR_WHITE)
  1239. print("")
  1240. print("Tape drives can be used as filesystems after formatting.")
  1241. print("Use FORMAT <drive> to format a tape for file storage.")
  1242. print("")
  1243.  
  1244. -- List current tape assignments
  1245. print("Current tape assignments:")
  1246. local tapes = os.tape.listTapes()
  1247. if #tapes == 0 then
  1248. print(" (none)")
  1249. else
  1250. for _, tape in ipairs(tapes) do
  1251. print(string.format(" %s: %s", tape.letter, tape.address:sub(1, 8)))
  1252. end
  1253. end
  1254. print("")
  1255.  
  1256. -- List available tape drives
  1257. print("Available tape drives:")
  1258. local component = component
  1259. local tapeIndex = 1
  1260. local tapeDrives = {}
  1261. for addr, ctype in component.list("tape_drive", true) do
  1262. print(string.format(" %d. %s", tapeIndex, addr:sub(1, 8)))
  1263. tapeDrives[tapeIndex] = addr
  1264. tapeIndex = tapeIndex + 1
  1265. end
  1266.  
  1267. if tapeIndex == 1 then
  1268. print(" (none available)")
  1269. return
  1270. end
  1271.  
  1272. print("")
  1273. print("Enter number to assign (or 0 to cancel):")
  1274. local choice = readLine("> ")
  1275. choice = tonumber(choice)
  1276.  
  1277. if not choice or choice == 0 then
  1278. print("Cancelled")
  1279. return
  1280. end
  1281.  
  1282. if not tapeDrives[choice] then
  1283. os.display.setForeground(COLOR_RED)
  1284. print("Invalid choice")
  1285. os.display.setForeground(COLOR_WHITE)
  1286. return
  1287. end
  1288.  
  1289. print("Enter drive letter (A-Z):")
  1290. local letter = readLine("> ")
  1291. letter = os.string.trim(letter):upper()
  1292.  
  1293. if #letter ~= 1 or letter < "A" or letter > "Z" then
  1294. os.display.setForeground(COLOR_RED)
  1295. print("Invalid drive letter")
  1296. os.display.setForeground(COLOR_WHITE)
  1297. return
  1298. end
  1299.  
  1300. local ok, err = os.tape.setTape(letter, tapeDrives[choice])
  1301. if ok then
  1302. os.display.setForeground(COLOR_GREEN)
  1303. print(string.format("Tape %s: assigned to %s", letter, tapeDrives[choice]:sub(1, 8)))
  1304. print("Use FORMAT " .. letter .. ": to format it as a filesystem")
  1305. os.display.setForeground(COLOR_WHITE)
  1306. else
  1307. os.display.setForeground(COLOR_RED)
  1308. print("Failed to assign tape: " .. tostring(err))
  1309. os.display.setForeground(COLOR_WHITE)
  1310. end
  1311. end
  1312.  
  1313. -- ==================== COMMAND PARSER ====================
  1314. local function parseCommand(input)
  1315. input = os.string.trim(input)
  1316. if input == "" then return nil, {} end
  1317.  
  1318. -- Check if it's a drive change command (e.g., "D:")
  1319. if input:match("^[A-Za-z]:$") then
  1320. local letter = input:sub(1, 1):upper()
  1321. -- Check both filesystems and tapes
  1322. if os.fs.getDrive(letter) then
  1323. currentDrive = letter
  1324. os.fs.setCurrentDrive(letter)
  1325. currentDir = "/"
  1326. return nil, {}
  1327. elseif os.tape.getTape(letter) then
  1328. os.display.setForeground(COLOR_YELLOW)
  1329. print("Note: " .. letter .. ": is a tape drive, not a filesystem")
  1330. os.display.setForeground(COLOR_WHITE)
  1331. return nil, {}
  1332. else
  1333. os.display.setForeground(COLOR_RED)
  1334. print("Invalid drive: " .. letter .. ":")
  1335. os.display.setForeground(COLOR_WHITE)
  1336. return nil, {}
  1337. end
  1338. end
  1339.  
  1340. local parts = os.string.split(input, " ")
  1341. local cmd = table.remove(parts, 1)
  1342. return string.lower(cmd), parts
  1343. end
  1344.  
  1345. -- ==================== MAIN LOOP ====================
  1346. local function main()
  1347. clearScreen()
  1348.  
  1349. os.display.setForeground(COLOR_YELLOW)
  1350. print("Monolith Disk Operating System (M-DOS)")
  1351. print("Version 1.02")
  1352. os.display.setForeground(COLOR_WHITE)
  1353. print("")
  1354.  
  1355. -- Show connected drives
  1356. local component = component
  1357. local bootAddr = computer.getBootAddress()
  1358. os.display.setForeground(COLOR_GREEN)
  1359. print("Boot drive: A: (" .. bootAddr:sub(1, 8) .. ")")
  1360. os.display.setForeground(COLOR_WHITE)
  1361. print("")
  1362.  
  1363. print("Connected filesystems:")
  1364. local driveCount = 0
  1365. local tmpAddr = computer.tmpAddress()
  1366. for addr, ctype in component.list("filesystem", true) do
  1367. -- Skip tmpfs
  1368. if addr ~= tmpAddr then
  1369. driveCount = driveCount + 1
  1370. local isBootDrive = (addr == bootAddr)
  1371. local proxy = component.proxy(addr)
  1372. local label = proxy.getLabel() or "Unlabeled"
  1373. local capacity = proxy.spaceTotal and proxy.spaceTotal() or 0
  1374. local deviceType = "Filesystem"
  1375.  
  1376. if ctype == "filesystem" then
  1377. -- Try to determine if it's a floppy or hard drive based on capacity
  1378. if capacity < 1024 * 1024 then
  1379. deviceType = "Floppy"
  1380. else
  1381. deviceType = "Hard Drive"
  1382. end
  1383. end
  1384.  
  1385. if isBootDrive then
  1386. os.display.setForeground(COLOR_GREEN)
  1387. print(string.format(" A: %s - %s (%s)", addr:sub(1, 8), formatSize(capacity), deviceType))
  1388. os.display.setForeground(COLOR_WHITE)
  1389. else
  1390. -- Check if already assigned
  1391. local assigned = false
  1392. for letter, driveProxy in pairs(os.fs.drives) do
  1393. if driveProxy.address == addr then
  1394. os.display.setForeground(COLOR_YELLOW)
  1395. print(string.format(" %s: %s - %s (%s)", letter, addr:sub(1, 8), formatSize(capacity), deviceType))
  1396. os.display.setForeground(COLOR_WHITE)
  1397. assigned = true
  1398. break
  1399. end
  1400. end
  1401. if not assigned then
  1402. print(string.format(" %s - %s (%s) [unassigned]", addr:sub(1, 8), formatSize(capacity), deviceType))
  1403. end
  1404. end
  1405. end
  1406. end
  1407.  
  1408. -- Show connected tape drives
  1409. print("")
  1410. print("Connected tape drives:")
  1411. local tapeCount = 0
  1412. for addr, ctype in component.list("tape_drive", true) do
  1413. tapeCount = tapeCount + 1
  1414. local proxy = component.proxy(addr)
  1415. local size = proxy.getSize and proxy.getSize() or 0
  1416. local label = proxy.getLabel and proxy.getLabel() or "No Tape"
  1417.  
  1418. -- Check if already assigned
  1419. local assigned = false
  1420. local isFormatted = false
  1421. for letter, tapeProxy in pairs(os.tape.tapes) do
  1422. if tapeProxy.address == addr then
  1423. assigned = true
  1424. -- Check if formatted
  1425. local fs = os.tape.readTapeFS(tapeProxy)
  1426. isFormatted = (fs ~= nil)
  1427.  
  1428. os.display.setForeground(COLOR_YELLOW)
  1429. if isFormatted then
  1430. print(string.format(" %s: %s - %s (TapeFS - Ready)", letter, addr:sub(1, 8), formatSize(size)))
  1431. else
  1432. print(string.format(" %s: %s - %s (Tape - Not Formatted)", letter, addr:sub(1, 8), formatSize(size)))
  1433. end
  1434. os.display.setForeground(COLOR_WHITE)
  1435. break
  1436. end
  1437. end
  1438. if not assigned then
  1439. print(string.format(" %s - %s (Tape Drive) [unassigned]", addr:sub(1, 8), formatSize(size)))
  1440. end
  1441. end
  1442.  
  1443. if tapeCount == 0 then
  1444. print(" (none)")
  1445. end
  1446.  
  1447. if driveCount > 1 or tapeCount > 0 then
  1448. print("")
  1449. os.display.setForeground(COLOR_GRAY)
  1450. if driveCount > 1 then
  1451. print("Use FDISK to assign drive letters to unassigned filesystems")
  1452. end
  1453. if tapeCount > 0 then
  1454. print("Use FTAPE to assign drive letters to tape drives")
  1455. end
  1456. os.display.setForeground(COLOR_WHITE)
  1457. end
  1458.  
  1459. print("")
  1460. print("Type HELP for available commands")
  1461. print("")
  1462.  
  1463. while running do
  1464. local prompt = currentDrive .. ":" .. currentDir .. "> "
  1465. local input = readLine(prompt)
  1466.  
  1467. if input and input ~= "" then
  1468. -- Add to command history
  1469. if #commandHistory == 0 or commandHistory[#commandHistory] ~= input then
  1470. table.insert(commandHistory, input)
  1471. if #commandHistory > historySize then
  1472. table.remove(commandHistory, 1)
  1473. end
  1474. end
  1475.  
  1476. local cmd, args = parseCommand(input)
  1477.  
  1478. if cmd and commands[cmd] then
  1479. commands[cmd](args)
  1480. elseif cmd then
  1481. os.display.setForeground(COLOR_RED)
  1482. print("Unknown command: " .. cmd)
  1483. print("Type HELP for available commands")
  1484. os.display.setForeground(COLOR_WHITE)
  1485. end
  1486. end
  1487. end
  1488.  
  1489. print("Goodbye!")
  1490. end
  1491.  
  1492. -- Start the command interpreter
  1493. main()
Advertisement
Add Comment
Please, Sign In to add comment