This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
Cyclonit's profile picture

[1.33] CycloDat v0.2

Started by Cyclonit, 24 July 2012 - 07:32 PM
Cyclonit #1
Posted 24 July 2012 - 09:32 PM
Introduction

Hi 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 computer's (or turtle's) directory on your PC and thus cannot be shared between computers or turtles using this API.

If you have any bug reports, suggestions or general feedback on how I could improve this API please let me know =)

-Cyclonit


Features:
  • easy to use
  • type persistence
  • supports all primitive types
How to

Installing the API:
  1. Download the API using this link: Mediafire download or by copying it from the Pastebin site.
  2. Download my CycloFramwork API using this link: Mediafire download or by copying it from the Pastebin site.
  3. Move both files into "modsComputerCraftluaromapis"
  4. Optional: You must remove any file extensions from the downloaded files, if your PC decided to add them.
  5. Optional: Load the APIs using "os.loadAPI("/rom/apis/cd")" and "os.loadAPI("/rom/apis/cd")" respectively. (Not necessary if you put the files into "modsComputerCraftluaromapis".)

Commands:
  1. save(string name, string/boolean/number/table value) - Saves the given value using the given name.
  2. saveRaw(string name, string value) - Saves the given value without converting it.
  3. load(string name) - Returns the stored value of the named variable.
  4. loadRaw(string name) - Returns the stored value of the named variable without converting it.
  5. delete(string name) - Deletes a variables value from the database.
  6. list() - Returns a list containing all stored variables.
  7. listPrint() - Prints a list containing all stored variables to the terminal.

Source Code

[indent=1]CycloDat v2.0: Pastebin[/indent]
[indent=1]CycloFramwork v2.0: Pastebin[/indent]


Changelog:

[indent=1]v0.2:[/indent]
  • split save(…) into save(…) and saveRaw(…) for higher flexibility
  • split load(…) into load(…) and loadRaw(…) for higher flexibility
  • moved conversion and text utility functions to the CycloFramework
Tiin57 #2
Posted 24 July 2012 - 09:45 PM
Good job.
KyleBoyer #3
Posted 25 July 2012 - 04:43 AM
Introduction

Hi 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 to

Installing the API:
  1. Download the API using this link: Mediafire download.
  2. Move the file into "modsComputerCraftluaromapis"
  3. Load the API using "os.loadAPI("/rom/apis/CycloDat")"
Commands:
  1. save(string name, string/boolean/number/table value) - Saves the given value using the given name.
  2. load(string name) - Returns the stored value of the named variable.
  3. 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]
I would love to use this but I cannot figure out how to. :/
Sxw #4
Posted 25 July 2012 - 05:10 AM
Awesome, ima use this in my first (useful) program.
Cyclonit #5
Posted 25 July 2012 - 08:11 AM
@KyleBoyler: Did you follow the steps in the installation section? As soon as you did that you can use the commands by writing "CycloDat." and the command right after.
Calculator #6
Posted 27 July 2012 - 01:57 PM
Nice work, but did you know that ComputerCraft already comes with functions to encode tables to strings and decode them afterwards?
You should check out textutils.serialize(table) and textutils.unserialize(string). :)/>/>
Cyclonit #7
Posted 27 July 2012 - 03:10 PM
@Calculator: I knew that but it seems as if my function is more stable than the build in ones. Both ways were tested by myself and the serialize+unserialize method breaks at about 24000 table elements. Since my method additionally in most cases is as fast as the build in one and pretty much as often faster as it is slower, I do not see any reason to use serialize and unserialize ^^.


P.S.: I used randomly generated tables for testing. They contained strings, numbers, booleans and additional tables.
Cyclonit #8
Posted 03 August 2012 - 08:19 PM
Version 0.2 is now online. I optimized some of the functions and reorganized them for better compatibility with upcoming APIs. I did not test this API under 1.4 yet. Feedback is appreciated =)