IntroductionHi there,
over the past few days, I have been working on an API for saving variables beyond the runtime of computers and turtles. The resulting code enables storing of numbers, strings, booleans, tables and nested tables. Saved variables can be found in the file called "database" in your computers (or turtles) directory on your PC and thus cannot be shared between computers or turtles using this API.
If you have any suggestions on how I could improve this API please let me know =)
-Cyclonit
Features:- easy to use
- type persistence
- supports all primitive types
How toInstalling the API:
- Download the API using this link: Mediafire download.
- Move the file into "modsComputerCraftluaromapis"
- Load the API using "os.loadAPI("/rom/apis/CycloDat")"
Commands:
- save(string name, string/boolean/number/table value) - Saves the given value using the given name.
- load(string name) - Returns the stored value of the named variable.
- delete(string name) - Deletes a variables value from the database.
Additional commands:
- list() - Returns a table containing all currently saved variables as keys for their respective values.
Source Code[indent=1]
Spoiler
------------------------------------------------------------
-- CycloDat --
-- --
-- Author: Christopher "Cyclonit" Klinge --
-- Contact: cyclonit@gmx.de --
-- 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
[/indent]