Welcome to mirror list, hosted at ThFree Co, Russian Federation.

persist.lua « luarocks « src - github.com/torch/luajit-rocks.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 9d601a4313929a6c379a4439bc3087b144d6cd83 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187

--- Utility module for loading files into tables and
-- saving tables into files.
-- Implemented separately to avoid interdependencies,
-- as it is used in the bootstrapping stage of the cfg module.
--module("luarocks.persist", package.seeall)
local persist = {}
package.loaded["luarocks.persist"] = persist

local util = require("luarocks.util")

--- Load a Lua file containing assignments, storing them in a table.
-- The global environment is not propagated to the loaded file.
-- @param filename string: the name of the file.
-- @param tbl table or nil: if given, this table is used to store
-- loaded values.
-- @return table or (nil, string): a table with the file's assignments
-- as fields, or nil and a message in case of errors.
function persist.load_into_table(filename, tbl)
   assert(type(filename) == "string")
   assert(type(tbl) == "table" or not tbl)

   local result, chunk, ran, err
   result = tbl or {}
   local globals = {}
   local globals_mt = {
      __index = function(t, n)
         globals[n] = true
         return rawget(t, n)
      end
   }
   local save_mt = getmetatable(result)
   setmetatable(result, globals_mt)
   if _VERSION == "Lua 5.1" then -- Lua 5.1
      chunk, err = loadfile(filename)
      if chunk then
         setfenv(chunk, result)
         ran, err = pcall(chunk)
      end
   else -- Lua 5.2
      chunk, err = loadfile(filename, "t", result)
      if chunk then
         ran, err = pcall(chunk)
      end
   end
   setmetatable(result, save_mt)
   
   if not chunk then
      if err:sub(1,5) ~= filename:sub(1,5) then
         return false, err
      end
      return nil, "Error loading file: "..err
   end
   if not ran then
      return nil, "Error running file: "..err
   end
   return result, globals
end

local write_table

--- Write a value as Lua code, invoking write_table.
-- This function handles only numbers, strings and tables
-- are keys (tables are handled recursively).
-- @param out userdata: a file object, open for writing.
-- @param v: the value to be written.
-- @param level number: the indentation level
-- @param sub_order table: optional prioritization table
-- @see write_table
local function write_value(out, v, level, sub_order)
   if type(v) == "table" then
      write_table(out, v, level + 1, sub_order)
   elseif type(v) == "string" then
      if v:match("\n") then
         local open, close = "[[", "]]"
         local equals = 0
         while v:find(open,1,true) or v:find(close,1,true) do
            equals = equals + 1
            local eqs = ("="):rep(equals)
            open, close = "["..eqs.."[", "]"..eqs.."]"
         end
         out:write(open.."\n"..v..close)
      else
         out:write("\""..v:gsub("\"", "\\\"").."\"")
      end
   else
      out:write(tostring(v))
   end
end

--- Write a table as Lua code representing a table to disk
-- (that is, in curly brackets notation).
-- This function handles only numbers, strings and tables
-- are keys (tables are handled recursively).
-- @param out userdata: a file object, open for writing.
-- @param tbl table: the table to be written.
-- @param level number: the indentation level
-- @param field_order table: optional prioritization table
write_table = function(out, tbl, level, field_order)
   out:write("{")
   local sep = "\n"
   local indentation = "   "
   local indent = true
   local i = 1
   for k, v, sub_order in util.sortedpairs(tbl, field_order) do
      out:write(sep)
      if indent then
         for n = 1,level do out:write(indentation) end
      end
      sep = ",\n"
      indent = true
      if type(k) == "number" then
         if k ~= i then
            out:write("["..tostring(k).."]=")
         else
            i = i + 1
         end
         indent = false
         sep = ", "
      elseif type(k) == "table" then
         out:write("[")
         write_table(out, k, level + 1)
         out:write("] = ")
      else
         if k:match("^[a-zA-Z_][a-zA-Z0-9_]*$") then
            out:write(k.." = ")
         else
            out:write("['"..k:gsub("'", "\\'").."'] = ") 
         end
      end
      write_value(out, v, level, sub_order)
   end
   if sep ~= "\n" then
      out:write("\n")
      for n = 1,level-1 do out:write(indentation) end
   end
   out:write("}")
end

--- Writes a table to an io-like object.
-- @param out userdata: a file object, open for writing.
-- @param tbl table: the table to be written.
-- @param field_order table: optional prioritization table
-- @return userdata The file object originally passed in as the `out` parameter.
local function write_table(out, tbl, field_order)
   for k, v, sub_order in util.sortedpairs(tbl, field_order) do
      out:write(k.." = ")
      write_value(out, v, 0, sub_order)
      out:write("\n")
   end
   return out
end

--- Save the contents of a table to a string.
-- Each element of the table is saved as a global assignment.
-- Only numbers, strings and tables (containing numbers, strings
-- or other recursively processed tables) are supported.
-- @param tbl table: the table containing the data to be written
-- @param field_order table: an optional array indicating the order of top-level fields.
-- @return string
function persist.save_from_table_to_string(tbl, field_order)
   local out = {buffer = {}}
   function out:write(data) table.insert(self.buffer, data) end
   write_table(out, tbl, field_order)
   return table.concat(out.buffer)
end

--- Save the contents of a table in a file.
-- Each element of the table is saved as a global assignment.
-- Only numbers, strings and tables (containing numbers, strings
-- or other recursively processed tables) are supported.
-- @param filename string: the output filename
-- @param tbl table: the table containing the data to be written
-- @param field_order table: an optional array indicating the order of top-level fields.
-- @return boolean or (nil, string): true if successful, or nil and a
-- message in case of errors.
function persist.save_from_table(filename, tbl, field_order)
   local out = io.open(filename, "w")
   if not out then
      return nil, "Cannot create file at "..filename
   end
   write_table(out, tbl, field_order)
   out:close()
   return true
end

return persist