-- This file is part of Reno desktop. -- -- Reno desktop is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. -- -- Reno desktop is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. -- -- You should have received a copy of the GNU General Public License along with Reno desktop. If not, see . -- Various utilitiy parsers local parsers = {} local function split_strings(text) -- probably the cleanest function to split by strings i've written local split = {} while text:find("\"") do local strstart = text:find("\"") while text:sub(strstart-1,strstart-1) == "\\" do strstart = text:find("\"",strstart+1) end local strend = text:find("\"",strstart+1) while text:sub(strend-1,strend-1) == "\\" do strend = text:find("\"",strend+1) end if not strend then return nil, "String not closed at "..strstart end local before_string = text:sub(1,strstart-1) local string = text:sub(strstart,strend):gsub("\\\"","\"") text = text:sub(strend+1,-1) table.insert(split,before_string) table.insert(split,string) end table.insert(split,text) return split end parsers.fast_split_yaml = function(cfgtext) -- Fast yaml splitter - incomplete parsing, only first layer is parsed -- Used within timers to find objects while decreasing CPU usage local items = {} local replacements = 1 cfgtext = cfgtext:gsub("^%s*","") while replacements > 0 do cfgtext,replacements = cfgtext:gsub("^(.-\n)(%S+)",function(struct,n) table.insert(items,struct) return ""..n end) end table.insert(items,cfgtext) return items end parsers.yaml_pseudo = function(cfgtext) -- Somewhat yaml-like structure used by pactl local struct = {} local lines = {} cfgtext:gsub("(%s*)([^\n]*)",function(spacing,line) table.insert(lines, { spacing:len(), -- key line:match("^([^:=]-)%s*[:=]") or line, -- value line:match(":%s*(.-)%s*$") or line:match("=%s*(.-)%s*$") } ) end) local history = {struct} local spacing_width = 0 for k,v in pairs(lines) do if v[1] > spacing_width then history[#history][lines[k-1][2]] = { [lines[k-1][2]] = lines[k-1][3] } history[#history+1] = history[#history][lines[k-1][2]] elseif v[1] < spacing_width then history[#history] = nil end if v[3] and v[3]:match("^%s*\".*\"%s*$") then history[#history][v[2]] = v[3]:match("^%s*\"(.*)\"%s*$") else history[#history][v[2]] = v[3] end spacing_width = v[1] end return struct end parsers.conf = function(cfgtext) -- Conf style parser (not exactly TOML) cfgtext = cfgtext:gsub("#[^\n]*","") local split_by_strings,err = split_strings(cfgtext) if not split_by_strings then error(err) end local struct = {global = {}} local block = "global" local last_string_key = nil local err for k,v in pairs(split_by_strings) do if not v:match("^\".*\"$") then v:gsub("[^\n]*",function(line) -- Nothing if line:match("^%s*$") then return end -- Namespace block if line:match("^%s*%[[^%]]-%]%s*$") then block = line:match("%[([^%]]-)%]") struct[block] = {} return end -- String/Multiline string assignment if line:match("^%s*[^=]-%s*=%s*$") then last_string_key = line:match("^%s*([^=]-)%s*=%s*$") return end -- Number/boolean assignment local key,value = line:match("^%s*([^=]-)%s*=%s*(.-)%s*$") -- number if value:match("^[%d%.]*$") then value = tonumber(value) -- bool elseif (value:lower() == "yes") or (value:lower() == "no") then value = (value:lower() == "yes") end struct[block][key] = value end) else struct[block][last_string_key] = v:sub(2,-2) end end return struct end return parsers