summaryrefslogtreecommitdiffstats
path: root/format.lua
diff options
context:
space:
mode:
Diffstat (limited to 'format.lua')
-rw-r--r--format.lua512
1 files changed, 512 insertions, 0 deletions
diff --git a/format.lua b/format.lua
new file mode 100644
index 0000000..0076fdf
--- /dev/null
+++ b/format.lua
@@ -0,0 +1,512 @@
+--[[
+ module for format changes in tables and strings
+ try to keep non input specific
+]]--
+
+module (..., package.seeall)
+
+-- find all return characters and removes them, may get this from a browser
+-- that is why didn't do file specific
+
+function dostounix ( str )
+ local data = string.gsub(str, "\r", "")
+ return data
+end
+
+-- Escape Lua magic characters
+function escapemagiccharacters ( str )
+ return (string.gsub(str or "", "[%(%)%.%%%+%-%*%?%[%]%^%$]", "%%%1"))
+end
+
+-- Escape shell special characters
+function escapespecialcharacters ( str )
+ return (string.gsub(str or "", "[~`#%$&%*%(%)\\|%[%]{};\'\"<>/]", "\\%1"))
+end
+
+-- search and remove all blank and commented lines from a string or table of lines
+-- returns a table to iterate over without the blank or commented lines
+
+function parse_lines ( input, comment )
+ local lines = {}
+ comment = comment or "#"
+
+ function parse(line)
+ if not string.match(line, "^%s*$") and not string.match(line, "^%s*"..comment) then
+ lines[#lines + 1] = line
+ end
+ end
+
+ if type(input) == "string" then
+ for line in string.gmatch(input, "([^\n]*)\n?") do
+ parse(line)
+ end
+ elseif type(input) == "table" then
+ for i,line in ipairs(input) do
+ parse(line)
+ end
+ end
+
+ return lines
+end
+
+-- search and remove all blank and commented lines from a string or table of lines
+-- parse the lines for words, looking for quotes and removing comments
+-- returns a table with an array of words for each line
+
+function parse_linesandwords ( input, comment )
+ local lines = {}
+ local linenum = 0
+ comment = comment or "#"
+
+ function parse(line)
+ linenum = linenum + 1
+ if not string.match(line, "^%s*$") and not string.match(line, "^%s*"..comment) then
+ local linetable = {linenum=linenum, line=line}
+ local offset = 1
+ while string.find(line, "%S", offset) do
+ local word = string.match(line, "%S+", offset)
+ local endword
+ if string.find(word, "^"..comment) then
+ break
+ elseif string.find(word, "^\"") then
+ endword = select(2, string.find(line, "\"[^\"]*\"", offset))
+ word = string.sub(line, string.find(line, "\"", offset), endword)
+ else
+ endword = select(2, string.find(line, "%S+", offset))
+ end
+ table.insert(linetable, word)
+ offset = endword + 1
+ end
+ lines[#lines + 1] = linetable
+ end
+ end
+
+ if type(input) == "string" then
+ for line in string.gmatch(input, "([^\n]*)\n?") do
+ parse(line)
+ end
+ elseif type(input) == "table" then
+ for i,line in ipairs(input) do
+ parse(line)
+ end
+ end
+
+ return lines
+end
+
+-- returns a table with label value pairs
+
+function parse_configfile( input, comment )
+ local config = {}
+ local lines = parse_linesandwords(input, comment)
+
+ for i,linetable in ipairs(lines) do
+ config[linetable[1]] = table.concat(linetable, " ", 2) or ""
+ end
+ return config
+end
+
+-- search and replace through a table
+-- string is easy string.gsub(string, find, replace)
+
+function search_replace (input, find, replace)
+ local lines = {}
+ for i,line in ipairs(input) do
+ lines[#lines + 1] = string.gsub(line, find, replace)
+ end
+ return lines
+end
+
+-- great for line searches through a file. /etc/conf.d/ ???
+-- might be looking for more than one thing so will return a table
+-- will likely want to match whole line entries
+-- so we change find to include the rest of the line
+-- say want all the _OPTS from a file format.search_for_lines (fs.read_file("/etc/conf.d/cron"), "OPT")
+-- if want to avoid commented lines, call parse_lines first
+
+function search_for_lines (input, find)
+ local lines = {}
+
+ function findfn(line)
+ if string.find(line, find) then
+ lines[#lines + 1] = line
+ end
+ end
+
+ if type(input) == "string" then
+ for line in string.gmatch(input, "([^\n]*)\n?") do
+ findfn(line)
+ end
+ elseif type(input) == "table" then
+ for i,line in ipairs(input) do
+ findfn(line)
+ end
+ end
+
+ return lines
+end
+
+--string format function to capitalize the beginging of each word.
+function cap_begin_word ( str )
+ --first need to do the first word
+ local data = string.gsub(str, "^%l", string.upper)
+ --word is any space cause no <> regex
+ data = string.gsub(data, "%s%l", string.upper)
+ return data
+end
+
+--for cut functionality do something like
+--print(format.string_to_table("This is a test", " ")[2])
+--gives you the second field which is .... is
+
+-- This code comes from http://lua-users.org/wiki/SplitJoin
+-- example: format.string_to_table( "Anna, Bob, Charlie,Dolores", ",%s*")
+function string_to_table ( text, delimiter)
+ local list = {}
+ if text then
+ -- this would result in endless loops
+ if string.find("", delimiter) then
+ -- delimiter matches empty string!
+ for i=1,#text do
+ list[#list + 1] = string.sub(text, i, i)
+ end
+ else
+ local pos = 1
+ while 1 do
+ local first, last = string.find(text, delimiter, pos)
+ if first then -- found?
+ table.insert(list, string.sub(text, pos, first-1))
+ pos = last+1
+ else
+ table.insert(list, string.sub(text, pos))
+ break
+ end
+ end
+ end
+ end
+ return list
+end
+
+
+-- Takes a str and expands any ${...} constructs with the Lua variable
+-- ex: a="foo"; print(expand_bash_syntax_vars("a=${a}) - > "a=foo"
+expand_bash_syntax_vars = function (str)
+ local deref = function (f)
+ local v = getfenv(3) -- get the upstream global env
+ for w in string.gfind(f, "[%w_]+") do
+ if v then v = v[w] end
+ end
+ return v
+ end
+
+ for w in string.gmatch (str, "${[^}]*}" ) do
+ local rvar = string.sub(w,3,-2)
+ local rval = ( deref(rvar) or "nil" )
+ str = string.gsub (str, w, escapespecialcharacters(rval))
+ end
+
+ return (str)
+end
+
+-- Removes the linenum line from str and replaces it with line.
+-- Do nothing if doesn't exist
+-- Set line to nil to remove the line
+function replace_line(str, linenum, line)
+ -- Split the str to remove the line
+ local startchar, endchar = string.match(str, "^" .. string.rep("[^\n]*\n", linenum-1) .. "()[^\n]*\n?()")
+ if startchar and endchar then
+ local lines = {}
+ lines[1] = string.sub(str, 1, startchar-1)
+ lines[2] = string.sub(str, endchar, -1)
+ if line then
+ table.insert(lines, 2, line .. "\n")
+ end
+ str = table.concat(lines)
+ end
+ return str
+end
+
+-- Inserts the line into the str after the linenum (or at the end)
+function insert_line(str, linenum, line)
+ -- Split the str to remove the line
+ local startchar = string.match(str, "^" .. string.rep("[^\n]*\n", linenum) .. "()")
+ local lines = {}
+ if startchar then
+ lines[1] = string.sub(str, 1, startchar-1)
+ lines[2] = string.sub(str, startchar, -1)
+ else
+ lines[1] = str
+ end
+ if line then
+ table.insert(lines, 2, line .. "\n")
+ end
+ str = table.concat(lines)
+ return str
+end
+
+function get_line(str, linenum)
+ -- Split the str to remove the line
+ local startchar, endchar = string.match(str, "^" .. string.rep("[^\n]*\n", linenum-1) .. "()[^\n]*()")
+ local line
+ if startchar and endchar then
+ line = string.sub(str, startchar, endchar-1)
+ end
+ return line
+end
+
+-- Search the option string for separate options (-x or --xyz) and put them in a table
+function opts_to_table ( optstring, filter )
+ local optsparams
+ if optstring then
+ local optstr = optstring .. " "
+ for o in string.gmatch(optstr, "%-%-?%a+%s+[^-%s]*") do
+ local option = string.match(o, "%-%-?%a+")
+ if not filter or filter == option then
+ if not optsparams then optsparams = {} end
+ optsparams[option] = string.match(o, "%S*$")
+ end
+ end
+ end
+ return optsparams
+end
+
+-- Go through an options table and create the option string
+function table_to_opts ( optsparams )
+ local optstring = {}
+ for opt,val in pairs(optsparams) do
+ optstring[#optstring + 1] = opt
+ if val ~= "" then
+ optstring[#optstring + 1] = val
+ end
+ end
+ return table.concat(optstring, " ")
+end
+
+-- The following functions deal with ini files. ini files contain comments, sections, names and values
+-- commented lines begin with '#' or ';', in-line comments begin with '#' and run to the end of the line
+-- sections are defined by "[section]" on a line. Anything before the first section definition is in section ""
+-- name value pairs are defined by "name = value". Names and values may contain spaces but not '#'
+-- lines ending with '\' are continued on the next line
+
+
+-- Set a name=value pair in a string
+-- If search_section is undefined or "", goes in the default section
+-- If value is defined we put "search_name=value" into search_section
+-- If value is undefined, we clear search_name out of search section
+-- Try not to touch anything but the value we're interested in (although will combine multi-line into one)
+-- If the search_section is not found, we'll add it at the end of the string
+-- If the search_name is not found, we'll add it at the end of the section
+function update_ini_file (file, search_section, search_name, value)
+ if not file or not search_name or search_name == "" then
+ return file, false
+ end
+
+ search_section = search_section or ""
+ local new_conf_file = {}
+ local section = ""
+ local done = false
+ local skip_lines = {}
+ for l in string.gmatch(file, "([^\n]*)\n?") do
+ if done == false then
+ if string.find ( l, "\\%s*$" ) then
+ skip_lines[#skip_lines+1] = string.match(l, "^(.*)\\%s*$")
+ l = nil
+ else
+ if #skip_lines then
+ skip_lines[#skip_lines+1] = l
+ l = table.concat(skip_lines, " ")
+ end
+ -- check if comment line
+ if not string.find ( l, "^%s*[#;]" ) then
+ -- find section name
+ local a = string.match ( l, "^%s*%[%s*(%S+)%s*%]" )
+ if a then
+ -- we reached a new section, if we were in the one we wanted
+ -- we have to add in the name:value pair now
+ if (search_section == section) then
+ new_conf_file[#new_conf_file + 1] = search_name.."="..value
+ done = true
+ end
+ section = a
+ elseif (search_section == section) then
+ -- find name
+ a = string.match ( l, "^%s*([^=]*%S)%s*=" )
+ if a and (search_name == a) then
+ -- We found the name, change the value, keep any comment
+ local comment = string.match(l, " #.*$") or ""
+ l = search_name.."="..value..comment
+ skip_lines = {} -- replacing line
+ done = true
+ end
+ end
+ end
+ if #skip_lines > 0 then
+ for i,line in ipairs(skip_lines) do
+ new_conf_file[#new_conf_file + 1] = line
+ end
+ skip_lines = {}
+ l = nil
+ end
+ end
+ end
+ new_conf_file[#new_conf_file + 1] = l
+ end
+
+ if done == false then
+ -- we didn't find the section:name, add it now
+ if section ~= search_section then
+ new_conf_file[#new_conf_file + 1] = '[' .. search_section .. ']'
+ end
+ new_conf_file[#new_conf_file + 1] = search_name.."="..value
+ end
+
+ file = table.concat(new_conf_file, '\n')
+
+ return file, true
+end
+
+-- Parse string for name=value pairs, returned in a table
+-- If search_section is defined, only report values in matching section
+-- If search_name is defined, only report matching name (possibly in multiple sections)
+function parse_ini_file (file, search_section, search_name)
+ if not file or file == "" then
+ return nil
+ end
+ local opts = nil
+ local section = ""
+ local skip_lines = {}
+ for l in string.gmatch(file, "([^\n]*)\n?") do
+ if string.find ( l, "\\%s*$" ) then
+ skip_lines[#skip_lines+1] = string.match(l, "^(.*)\\%s*$")
+ else
+ if #skip_lines then
+ skip_lines[#skip_lines+1] = l
+ l = table.concat(skip_lines, " ")
+ skip_lines = {}
+ end
+ -- check if comment line
+ if not string.find ( l, "^%s*[#;]" ) then
+ -- find section name
+ local a = string.match ( l, "^%s*%[%s*(%S+)%s*%]" )
+ if a then
+ if (search_section == section) then break end
+ section = a
+ elseif not (search_section) or (search_section == section) then
+ -- find name
+ a = string.match ( l, "^%s*([^=]*%S)%s*=" )
+ if a and (not (search_name) or (search_name == a)) then
+ -- Figure out the value
+ local b = string.match ( l, '=%s*(.*)$' ) or ""
+ -- remove comments from end of line
+ if string.find ( b, '#' ) then
+ b = string.match ( b, '^(.*)#.*$' ) or ""
+ end
+ -- remove spaces from front and back
+ b = string.gsub ( b, '%s+$', '' )
+ if not (opts) then opts = {} end
+ if not (opts[section]) then opts[section] = {} end
+ opts[section][a] = b
+ end
+ end
+ end
+ end
+ end
+
+ if opts and search_section and search_name then
+ return opts[search_section][search_name]
+ elseif opts and search_section then
+ return opts[search_section]
+ end
+ return opts
+end
+
+function get_ini_section (file, search_section)
+ if not file then
+ return nil
+ end
+ search_section = search_section or ""
+ local sectionlines = {}
+ local section = ""
+ for l in string.gmatch(file, "([^\n]*)\n?") do
+ -- find section name
+ local a = string.match ( l, "^%s*%[%s*(%S+)%s*%]" )
+ if a then
+ if (search_section == section) then break end
+ section = a
+ elseif (search_section == section) then
+ sectionlines[#sectionlines + 1] = l
+ end
+ end
+
+ return table.concat(sectionlines, "\n")
+end
+
+function set_ini_section (file, search_section, section_content)
+ if not file then
+ return file, false
+ end
+ search_section = search_section or ""
+ section_content = section_content or ""
+ local new_conf_file = {}
+ local done = false
+ local section = ""
+ if search_section == "" then new_conf_file[1] = section_content end
+ for l in string.gmatch(file, "([^\n]*)\n?") do
+ -- find section name
+ if not done then
+ local a = string.match ( l, "^%s*%[%s*(%S+)%s*%]" )
+ if a then
+ if (search_section == section) then
+ done = true
+ else
+ section = a
+ if (search_section == section) then
+ l = l .. "\n" .. section_content
+ end
+ end
+ elseif (search_section == section) then
+ l = nil
+ end
+ end
+ new_conf_file[#new_conf_file + 1] = l
+ end
+
+ if not done then
+ -- we didn't find the section, add it now
+ if section ~= search_section then
+ new_conf_file[#new_conf_file + 1] = '[' .. search_section .. ']'
+ new_conf_file[#new_conf_file + 1] = section_content
+ end
+ end
+
+ file = table.concat(new_conf_file, '\n')
+
+ return file, true
+end
+
+-- Find the value of an entry allowing for parent section and $variables
+-- the file parameter can be a string or structure returned by parse_ini_file
+-- beginning and ending quotes are removed
+-- returns value or "" if not found
+function get_ini_entry (file, section, value)
+ local opts = file
+ if not file or not value then
+ return nil
+ elseif type(file) == "string" then
+ opts = parse_ini_file(file)
+ end
+ section = section or ""
+ local result = opts[section][value]
+ if not result then
+ section = ""
+ result = opts[section][value] or ""
+ end
+ while string.find(result, "%$[%w_]+") do
+ local sub = string.match(result, "%$[%w_]+")
+ result = string.gsub(result, escapemagiccharacters(sub), get_ini_entry(opts, section, sub))
+ end
+ if string.find(result, '^"') and string.find(result, '"$') then
+ result = string.sub(result, 2, -2)
+ end
+ return result
+end