ldd-CC/mtape.lua

387 lines
11 KiB
Lua

-- Mtape
-- tape managing program
-- made by LDDestroier
local _DEBUG = false
local function checkOption(argName, argInfo, isShort)
for i = 1, #argInfo do
if argInfo[i][isShort and 2 or 3] == argName then
return i
end
end
return false
end
local function argParse(argInput, argInfo)
local sDelim = "-"
local lDelim = "--"
local optOutput = {}
local argOutput = {}
local argError = {}
local usedTokens = {}
local lOpt, sOpt, optNum
for i = 1, #argInfo do
optOutput[i] = {}
end
for i = 1, #argInput do
lOpt = argInput[i]
-- check type of delimiter
if lOpt:sub(1, #lDelim) == lDelim then
-- handle long delimiter
lOpt = lOpt:sub(#lDelim + 1)
optNum = checkOption(lOpt, argInfo, false)
if optNum then
if argInfo[optNum][1] == 0 then
optOutput[optNum] = true
else
optOutput[optNum] = {}
for ii = 1, argInfo[optNum][1] do
if argInput[i + ii] then
optOutput[optNum][#optOutput[optNum] + 1] = argInput[i + ii]
usedTokens[i + ii] = true
else
argError[#argError + 1] = "expected parameter " .. tostring(ii) .. " for argument " .. lDelim .. lOpt
break
end
end
i = i + argInfo[optNum][1]
end
else
argError[#argError + 1] = "invalid argument " .. lDelim .. lOpt
end
elseif lOpt:sub(1, #sDelim) == sDelim then
-- handle short delimiter
lOpt = lOpt:sub(#sDelim + 1)
for si = 1, #lOpt do
sOpt = lOpt:sub(si, si)
optNum = checkOption(sOpt, argInfo, true)
if optNum then
if argInfo[optNum][1] == 0 then
optOutput[optNum] = true
elseif si == #lOpt then
optOutput[optNum] = {}
for ii = 1, argInfo[optNum][1] do
if argInput[i + ii] then
optOutput[optNum][#optOutput[optNum] + 1] = argInput[i + ii]
usedTokens[i + ii] = true
else
argError[#argError + 1] = "expected parameter " .. tostring(ii) .. " for argument " .. sDelim .. sOpt
break
end
end
i = i + argInfo[optNum][1]
else
argError[#argError + 1] = "options with parameters must be at the end of their group"
break
end
else
argError[#argError + 1] = "invalid argument " .. sDelim .. sOpt
break
end
end
elseif not usedTokens[i] then
argOutput[#argOutput + 1] = lOpt
end
end
return argOutput, optOutput, argError
end
local function getHelp(specify)
if not specify then
print("mtape [file / url] (label)")
print("mtape [-i --info]")
print("mtape [-e --erase]")
print("mtape [-u --unclean]")
print("mtape [-c --cc-media]")
print("mtape [-u]")
print("Use -h with other options for details")
else
if specify == "--info" then
print("Prints information about the connected tape drive.")
print("This includes the label, size, minutes length, and current seeking position.")
elseif specify == "--erase" then
print("Erases the connected tape drive.")
elseif specify == "--unclean" then
print("Normally, tapes are erased before writing them anew. Use this option to not erase them first.")
print("If the tape has something longer written to it beforehand, you'll hear it after whatever is written now.")
elseif specify == "--ldd-github" then
print("Adds URL info from LDDestroier's personal CC-Media github to make it easier to pull from there.")
print("Ex. 'tapey -c krabii'")
print(" 'tapey -c simple'")
elseif specify == "--reinstall" then
print("Updates Mtape to the latest version on the LDDestroier/CC github.")
end
end
end
local tierInfo = {
-- damage value indicates type of tape
-- value of tierInfo indicates minutes of storage
[0] = 4,
[1] = 8,
[2] = 16,
[3] = 32,
[4] = 64,
[5] = 2,
[6] = 6,
[8] = 128
}
local function getFileContents(path, isURL)
local file, contents
if isURL then
file = http.get(path, nil, true)
else
file = fs.open(fs.combine(shell.dir(), path), "rb")
end
if not file then
return false, ""
else
contents = file.readAll()
file.close()
return true, contents
end
end
local function getTapeDrive(side)
local tape
if side then
tape = peripheral.wrap(side)
if not tape then
return false, "No such tape drive found.", 0
elseif peripheral.getType(tape) ~= "tape_drive" then
return false, "Not a tape drive.", 0
else
return true, tape, tape.getSize()
end
else
tape = peripheral.find("tape_drive")
if not tape then
return false, "Tape drive not connected.", 0
else
return true, tape, tape.getSize()
end
end
end
local function writeToTape(tape, contents, tapeName)
local output = ""
if not tape then error("expected tape peripheral") end
if not contents then error("expected contents") end
local totalTapeSize = tape.getSize()
if tapeName then
tape.setLabel(tapeName)
end
tape.stop()
tape.seek(-tape.getPosition())
if #contents > totalTapeSize then
output = "Tape too small, audio truncated."
for i = 0, 8 do
if tierInfo[i] then
if tierInfo[i] * 360000 >= #contents then
output = output .. "\nIt would fit on a" .. (tierInfo[i] == 8 and "n " or " ") .. tostring(tierInfo[i]) .. " minute tape."
break
end
end
end
contents = contents:sub(1, totalTapeSize)
end
tape.write(contents)
tape.seek(-tape.getPosition())
tape.stop()
return output
end
local function infoMode(tape)
local scr_x, scr_y = term.getSize()
print("Info for tape drive:")
print(("-"):rep(scr_x))
local gi = tape.getItem(1).getMetadata()
local info = {
inserted = gi ~= nil
}
local minute = 360000
if not info.inserted then
print("No tape inserted.")
else
info.displayname = gi.displayName
info.label = gi.media.label
info.itemname = gi.name
info.damage = gi.damage
info.minutes = tierInfo[info.damage]
info.maxsize = tape.getSize()
info.position = tape.getPosition()
print(info.displayname .. " inserted.")
print("Label: \"" .. info.label .. "\"")
write("Stores " .. tostring(info.minutes) .. " minutes")
print(" (" .. tostring(info.maxsize) .. " bytes)")
print("Seeked to " .. tostring(info.position) .. "/" .. tostring(info.maxsize))
end
return info
end
local argInfo = {
[1] = {0, "h", "help"},
[2] = {0, "i", "info"},
[3] = {1, "d", "drive"},
[4] = {0, "e", "erase"},
[5] = {0, "u", "unclean"},
[6] = {1, "c", "cc-media"},
[7] = {0, "r", "reinstall"}
}
local arguments, options, errors = argParse({...}, argInfo)
local tape, totalTapeSize, success, contents
if #errors > 0 then
for i = 1, #errors do
printError(errors[i])
end
return
end
local fileName = arguments[1]
local tapeName = arguments[2]
local tapeDriveName = options[3][1]
local wantedHelp = options[1] == true
local wantedInfo = options[2] == true
local wantedErase = options[4] == true
local doUnclean = options[5] == true
local getFromGithub = options[6][1]
local wantedUpdate = options[7] == true
if wantedHelp then
if wantedInfo then
getHelp("--info")
elseif wantedErase then
getHelp("--erase")
elseif doUnclean then
getHelp("--unclean")
elseif getFromGithub then
getHelp("--ldd-github")
elseif wantedUpdate then
getHelp("--reinstall")
else
getHelp()
end
return
end
if wantedUpdate then
print("Redownloading Mtape...")
local cpath = shell.getRunningProgram()
local file = http.get("https://github.com/LDDestroier/CC/raw/master/mtape.lua")
local contents
local sizeBefore = fs.getSize(cpath)
local sizeAfter = 0
if file then
contents = file.readAll()
sizeAfter = #contents
file.close()
file = fs.open(cpath, "w")
file.write(contents)
file.close()
print("Done! (diff: " .. tostring(sizeAfter - sizeBefore) .. " bytes)")
return
else
print("Couldn't update.")
return
end
end
-- Try to wrap specified tape drive OR find tape drive
success, tape, totalTapeSize = getTapeDrive(tapeDriveName)
if not success then
print(tape)
return
end
if wantedInfo then
infoMode(tape)
return true
end
if wantedErase then
success = writeToTape(tape, string.char(0):rep(tape.getSize()), tapeName)
print("Tape erased.")
return
end
if getFromGithub then
print("Pulling from CC-Media.")
tapeName = arguments[1]
fileName = "https://github.com/LDDestroier/CC-Media/raw/master/DFPWM/" .. getFromGithub .. ".dfpwm"
end
if not fileName then
getHelp()
return
end
-- Make file, and detect URL
if fileName:sub(1,8) == "https://" then
write("Downloading...")
success, contents = getFileContents(fileName, true)
print("Done.")
else
if not fs.exists(fileName) then
fileName = fileName .. ".dfpwm"
end
success, contents = getFileContents(fileName, false)
end
if not success then
error("Could not get file. Abort.")
else
if _DEBUG then
print("File size: " .. tostring(#contents) .. " bytes")
print("Tape size: " .. tostring(tape.getSize()) .. " bytes")
end
end
-- Adds null data to the end of the file if you want a clean tape write
if doUnclean then
print("Won't clean up tape first.")
else
contents = contents .. string.char(0):rep(math.max(0, totalTapeSize - #contents))
end
write("Writing...")
success = writeToTape(tape, contents, tapeName)
if success then
print("\n" .. success)
print("Nonetheless, it is written.")
else
print("done!")
end
return true