diff --git a/src/lua/csv.lua b/src/lua/csv.lua index b7c92c0cb94221715b8c5a6c8f15f31d18b58252..18fdc13112399c6adb87dc2579329dd00712257c 100644 --- a/src/lua/csv.lua +++ b/src/lua/csv.lua @@ -1,8 +1,7 @@ -- csv.lua (internal file) -do - -local ffi = require 'ffi' +local ffi = require('ffi') +local log = require('log') ffi.cdef[[ typedef void (*csv_emit_row_t)(void *ctx); @@ -29,6 +28,7 @@ ffi.cdef[[ void csv_create(struct csv *csv); void csv_destroy(struct csv *csv); void csv_setopt(struct csv *csv, int opt, ...); + struct csv_iterator { struct csv *csv; const char *buf_begin; @@ -51,12 +51,11 @@ ffi.cdef[[ }; ]] -iter = function(csvstate) +local iter = function(csvstate) local readable = csvstate[1] local csv_chunk_size = csvstate[2] local csv = csvstate[3] local it = csvstate[4] - local errlog = csvstate[5] local tup = {} local st = ffi.C.csv_next(it) while st ~= ffi.C.CSV_IT_EOF do @@ -67,7 +66,7 @@ iter = function(csvstate) elseif st == ffi.C.CSV_IT_OK then table.insert(tup, ffi.string(it[0].field, it[0].field_len)) elseif st == ffi.C.CSV_IT_ERROR then - errlog.warn("CSV file has errors") + log.warn("CSV file has errors") break elseif st == ffi.C.CSV_IT_EOF then break @@ -75,68 +74,65 @@ iter = function(csvstate) st = ffi.C.csv_next(it) end end -csv = { - -iterate = function(readable, csv_chunk_size) - csv_chunk_size = csv_chunk_size or 4096 - if type(readable.read) ~= "function" then - error("Usage: load(object with read method)") - end - local errlog = require('log') - local it = ffi.new('csv_iterator_t[1]') - local csv = ffi.new('csv_t[1]') - ffi.C.csv_create(csv) - ffi.C.csv_iter_create(it, csv) +local csv = { + iterate = function(readable, csv_chunk_size) + csv_chunk_size = csv_chunk_size or 4096 + if type(readable.read) ~= "function" then + error("Usage: load(object with read method)") + end - return iter, {readable, csv_chunk_size, csv, it, errlog} -end -, -load = function(readable, csv_chunk_size) - csv_chunk_size = csv_chunk_size or 4096 - if type(readable.read) ~= "function" then - error("Usage: load(object with read method)") - end - - result = {} - for tup in csv.iterate(readable, csv_chunk_size) do table.insert(result, tup) end - - return result -end -, -dump = function(writable, t) - if type(writable.write) ~= "function" or type(t) ~= "table" then - error("Usage: dump(writable, table)") - end - local csv = ffi.new('csv_t[1]') - ffi.C.csv_create(csv) - local bufsz = 256 - --local buf = ffi.new('char[?]', bufsz) - local buf = csv[0].csv_realloc(ffi.cast(ffi.typeof('void *'), 0), bufsz) - local it - if type(t[1]) ~= 'table' then - t = {t} - end - for k, line in pairs(t) do - local first = true - for k2, field in pairs(line) do - strf = tostring(field) - if (strf:len() + 1) * 2 > bufsz then - bufsz = (strf:len() + 1) * 2 - buf = csv[0].csv_realloc(buf, bufsz) + local it = ffi.new('csv_iterator_t[1]') + local csv = ffi.new('csv_t[1]') + ffi.C.csv_create(csv) + ffi.C.csv_iter_create(it, csv) + + return iter, {readable, csv_chunk_size, csv, it} + end, + load = function(readable, csv_chunk_size) + csv_chunk_size = csv_chunk_size or 4096 + if type(readable.read) ~= "function" then + error("Usage: load(object with read method)") + end + + result = {} + for tup in csv.iterate(readable, csv_chunk_size) do + table.insert(result, tup) + end + + return result + end, + dump = function(writable, t) + if type(writable.write) ~= "function" or type(t) ~= "table" then + error("Usage: dump(writable, table)") + end + local csv = ffi.new('csv_t[1]') + ffi.C.csv_create(csv) + local bufsz = 256 + --local buf = ffi.new('char[?]', bufsz) + local buf = csv[0].csv_realloc(ffi.cast(ffi.typeof('void *'), 0), bufsz) + if type(t[1]) ~= 'table' then + t = {t} + end + for k, line in pairs(t) do + local first = true + for k2, field in pairs(line) do + strf = tostring(field) + if (strf:len() + 1) * 2 > bufsz then + bufsz = (strf:len() + 1) * 2 + buf = csv[0].csv_realloc(buf, bufsz) + end + local len = ffi.C.csv_escape_field(csv, strf, buf) + if first then + first = false + else + writable:write(',') + end + writable:write(ffi.string(buf, len)) end - local len = ffi.C.csv_escape_field(csv, strf, buf) - if first then - first = false - else - writable:write(',') - end - writable:write(ffi.string(buf, len)) + writable:write('\n') end - writable:write('\n') + csv[0].csv_realloc(buf, 0) end - csv[0].csv_realloc(buf, 0) -end } return csv -end