diff options
author | Waqas Hussain <waqas20@gmail.com> | 2017-09-10 12:42:05 -0400 |
---|---|---|
committer | Waqas Hussain <waqas20@gmail.com> | 2017-09-10 12:42:05 -0400 |
commit | 347f3ab6a3e1f7f64a9289ec08c081f79bef9087 (patch) | |
tree | dd79dc2be53a0f2e4c0fa11da1374e8bf7fc38a1 | |
parent | 3888136262d43c5ca7ac20b50173d8957de96e58 (diff) | |
download | prosody-347f3ab6a3e1f7f64a9289ec08c081f79bef9087.tar.gz prosody-347f3ab6a3e1f7f64a9289ec08c081f79bef9087.zip |
util.format: A string.format wrapper that gracefully handles invalid arguments
-rw-r--r-- | util/format.lua | 74 |
1 files changed, 74 insertions, 0 deletions
diff --git a/util/format.lua b/util/format.lua new file mode 100644 index 00000000..5f2b12be --- /dev/null +++ b/util/format.lua @@ -0,0 +1,74 @@ +-- +-- A string.format wrapper that gracefully handles invalid arguments +-- + +local tostring = tostring; +local select = select; +local assert = assert; +local unpack = unpack; +local type = type; + +local function format(format, ...) + local args, args_length = { ... }, select('#', ...); + + -- format specifier spec: + -- 1. Start: '%%' + -- 2. Flags: '[%-%+ #0]' + -- 3. Width: '%d?%d?' + -- 4. Precision: '%.?%d?%d?' + -- 5. Option: '[cdiouxXaAeEfgGqs%%]' + -- + -- The options c, d, E, e, f, g, G, i, o, u, X, and x all expect a number as argument, whereas q and s expect a string. + -- This function does not accept string values containing embedded zeros, except as arguments to the q option. + -- a and A are only in Lua 5.2+ + + + -- process each format specifier + local i = 0; + format = format:gsub("%%[^cdiouxXaAeEfgGqs%%]*[cdiouxXaAeEfgGqs%%]", function(spec) + if spec ~= "%%" then + i = i + 1; + local arg = args[i]; + if arg == nil then -- special handling for nil + arg = "<nil>" + args[i] = "<nil>"; + end + + local option = spec:sub(-1); + if option == "q" or option == "s" then -- arg should be string + args[i] = tostring(arg); + elseif type(arg) ~= "number" then -- arg isn't number as expected? + args[i] = tostring(arg); + spec = "[%s]"; + end + end + return spec; + end); + + -- process extra args + while i < args_length do + i = i + 1; + local arg = args[i]; + if arg == nil then + args[i] = "<nil>"; + else + args[i] = tostring(arg); + end + format = format .. " [%s]" + end + + return format:format(unpack(args)); +end + +local function test() + assert(format("%s", "hello") == "hello"); + assert(format("%s") == "<nil>"); + assert(format("%s", true) == "true"); + assert(format("%d", true) == "[true]"); + assert(format("%%", true) == "% [true]"); +end + +return { + format = format; + test = test; +}; |