function trim(s) return (s:gsub("^%s*(.-)%s*$", "%1")) end function split_fmt(f) if not type(f) == "string" then io.stderr:write("ERROR! Argument '" .. format .. "' is not a string.") return nil end local ret = {} local curr = "" local in_spec = false for char in string.gmatch(f, ".") do if in_spec then if string.match(char, '[cdEefgiouXx]') then curr = curr .. char table.insert(ret, curr) in_spec = false curr = "" elseif string.match(char, '[qs]') then if string.match(curr, '^%%%-?[0-9]*$') then curr = curr .. char table.insert(ret, curr) in_spec = false curr = "" else io.stderr:write("Invalid format: '" .. curr .. char .. "'\n") return nil end elseif string.match(char, '[0-9%.%-]') then curr = curr .. char elseif string.match(char, '%%') then if string.match(curr, '^%%') then curr = curr .. char table.insert(ret, curr) in_spec = false curr = "" else io.stderr:write("Invalid format: '" .. curr .. char .. "'\n") return nil end else io.stderr:write("Invalid format: '" .. curr .. char .. "'\n") return nil end else if char == '%' then in_spec = true if curr ~= "" then table.insert(ret, curr) end curr = char else curr = curr .. char end end end if curr ~= "" then table.insert(ret, curr) end return ret end function table_length(t) local count = 0 for _ in pairs(t) do count = count + 1 end return count end function count_formats(formats) if type(formats) ~= 'table' then io.stderr:write("ERROR! formats is not a table.\n") return nil end local count = 0 for i,v in ipairs(formats) do if string.match(v, '^%%') and not string.match(v, '%%$') then count = count + 1 end end return count end function is_fmt_spec(str) return string.match(str, "^%%") end function conky_printf(format, ...) formats = split_fmt(format) values = {...} if count_formats(formats) ~= table_length(values) then io.stderr:write("ERROR! Number of format specifiers to printf doesn't match the number of values passed.\n") return nil end local parsed_values = {} for i,v in ipairs(values) do parsed_values[i] = conky_parse(v) end for i,fs in ipairs(formats) do if is_fmt_spec(fs) then -- we have a format specifier if string.match(fs, '[cdEefgiouXx]$') then -- we have a numeric format specifier, convert value to number parsed_values[i] = tonumber(trim((parsed_values[i]))) end end end local formatted_output = "" local idx = 1 for i,fs in ipairs(formats) do if is_fmt_spec(fs) then if not string.match(fs, '%%$') then formatted_output = formatted_output .. string.format(fs, parsed_values[idx]) idx = idx + 1 else formatted_output = formatted_output .. '%' end else formatted_output = formatted_output .. fs end end return formatted_output end