------------------------------------------------------------
-- CycloDat --
-- --
-- Author: Christopher "Cyclonit" Klinge --
-- Contact: [email protected] --
-- Version: 0.1 --
-- --
-- License: GNU General Public License v3.0 --
------------------------------------------------------------
---- >> DIRECTORIES/FILES << ----
-- Ensures existence of all necessary directories and files.
function makeDatabase()
-- directory
if (not fs.isDir("database")) then
fs.makeDir("database")
local db = fs.open("database/database", "w")
db.close()
return true
end
-- file
if (not fs.exists("database/database")) then
local db = fs.open("database/database", "w")
db.close()
return true
end
-- if both directory and file already exist return true
return true
end
---- >> CONVERSION << ----
-- Splits the given string count times in substrings between the given delimiter.
function splitString(str, delim, count)
local result = {}
-- split as often as possible if no maximum count is defined
if (count == nil) then
count = 10000
end
-- iterate through the string to inditify parts
local i = 1
while (i < #str) and (#result < count) do
-- found delimiter
if (string.sub(str, i, i) == delim) then
-- add the part in front of the delimiter to the result
table.insert(result, string.sub(str, 1, i-1))
str = string.sub(str, i+1)
i = 1
end
-- continue with the next character
i = i+1
end
-- add the last part to the results
if (str ~= "") then
result[#result + 1] = str
end
-- return
return result
end
-- Turns the given table into a string.
function tableToString(tbl)
local result = "{"
for key, value in pairs(tbl) do
-- format key and value
if (type(key) == "string") then
key = string.format("%q", key)
end
if (type(value) == "string") then
value = string.format("%q", value)
end
-- start recursion for nested tables
if (type(value) == "table") then
result = result .. "[" .. tostring(key) .. "]=" .. tableToString(value) .. ","
else
result = result .. "[" .. tostring(key) .. "]=" .. tostring(value) .. ","
end
end
-- remove the tailing "," and return
return string.sub(result, 1, -2) .. "}"
end
-- Converts the given variable into a line for the database.
function variableLine(var, value)
-- nil var
if (var == nil) or (var == "") then
return ""
-- number/boolean
elseif (type(value) == "number") or
(type(value) == "boolean") then
return var .. "=" .. tostring(value)
-- string
elseif (type(value) == "string") then
return var .. "="" .. value .. """
-- table
elseif (type(value) == "table") then
return var .. "=return " .. tableToString(value)
-- nil/unknown type
else
return var .. "=nil"
end
end
-- Converts the given line into a variable's name and value.
function decode(line)
-- return nil if there is no information stored in the line
if (line == "") or (line == nil) then
return nil, nil
end
-- split
local splitUp = splitString(line, "=", 1)
local var = splitUp[1]
local value = splitUp[2]
-- nil value
if (value == "nil") then
return var, nil
-- string
elseif (string.find(value .. "", """) == 1) then
return var, string.sub(value, 2, -2)
-- boolean
elseif (value == "true") then
return var, true
elseif (value == "false") then
return var, false
-- number
elseif (tonumber(value) ~= nil) then
return var, tonumber(value)
-- table
elseif (string.find(value .. "", "return ") == 1) then
value = loadstring(value)
return var, value()
end
-- unknown type
return nil
end
---- >> SAVING << ----
-- Saves the given variable using the given name.
function save(var, value)
-- ensure existence of the database
makeDatabase()
-- open the database
local db = fs.open("database/database", "r")
-- read all of the files lines, checking whether the variable already exists
local found = false
local lines = {}
local line = db.readLine() or nil
while (line ~= nil) do
-- decode the line
local lineVar, lineValue = decode(line)
-- overwrite the line if it contains the correct value
if (lineVar == var) then
-- insert the new line
lines[#lines + 1] = variableLine(var, value)
found = true
break
-- otherwise continue
else
lines[#lines + 1] = line
line = db.readLine() or nil
end
end
-- save the rest of the file
line = db.readLine()
while (line ~= nil) and (line ~= "") do
lines[#lines + 1] = line
line = db.readLine()
end
-- if the variable was not found, append the according line now
if (not found) then
lines[#lines + 1] = variableLine(var, value)
end
-- reopen the file to gain write access
db.close()
db = fs.open("database/database", "w")
-- write all lines to the file
for i=1, #lines, 1 do
db.write(lines[i] .. "n")
end
-- close the file and return
db.close()
return true
end
---- >> LOADING << ----
-- Lists all stored variables.
function list()
-- ensure existence of the database
makeDatabase()
-- open the database
local db = fs.open("database/database", "r")
if (not db) then
return {}
end
-- loop through all of the lines
local result = {}
local line = db.readLine() or nil
while (line ~= nil) do
-- decode the line
local lineVar, lineValue = decode(line)
-- add the line to the result
if (lineVar ~= nil) then
result[lineVar] = lineValue
end
-- continue with the next line
line = db.readLine() or nil
end
-- return
db.close()
return result
end
-- Loads the variable's value.
function load(var)
-- ensure existence of the database
makeDatabase()
-- open the database
local db = fs.open("database/database", "r")
if (not db) then
return nil
end
-- loop through all of the lines
local line = db.readLine() or nil
while (line ~= nil) do
-- decode the line
local lineVar, lineValue = decode(line)
-- return if this is the correct line
if (lineVar == var) then
return lineValue
end
-- continue with the next line
line = db.readLine() or nil
end
-- the variable was not found
return nil
end
---- >> DELETING << ----
-- Deletes the variable.
function delete(var)
-- ensure existence of the database
makeDatabase()
-- open the database
local db = fs.open("database/database", "r")
if (not db) then
return nil
end
-- loop through all of the lines
local lines = {}
local line = db.readLine() or nil
while (line ~= nil) do
-- decode the line
local lineVar, lineValue = decode(line)
-- save the line if it does not contain the chosen variable
if (lineVar ~= var) then
lines[#lines + 1] = line
end
-- continue with the next line
line = db.readLine() or nil
end
-- reopen the file to gain write access
db.close()
db = fs.open("database/database", "w")
-- write all lines to the file
for i=1, #lines, 1 do
db.write(lines[i] .. "n")
end
-- close the database and return
db.close()
return true
end