Software /
code /
prosody
Comparison
util/format.lua @ 10046:0bc291a5734a
Merge 0.11->trunk
author | Kim Alvefur <zash@zash.se> |
---|---|
date | Mon, 10 Jun 2019 13:22:22 +0200 |
parent | 10035:386f085820e6 |
child | 11638:5f4a657136bc |
comparison
equal
deleted
inserted
replaced
10045:6714578cfd6e | 10046:0bc291a5734a |
---|---|
1 -- | 1 -- |
2 -- A string.format wrapper that gracefully handles invalid arguments | 2 -- A string.format wrapper that gracefully handles invalid arguments |
3 -- | 3 -- |
4 | 4 |
5 local tostring = tostring; | 5 local tostring = tostring; |
6 local select = select; | |
7 local unpack = table.unpack or unpack; -- luacheck: ignore 113/unpack | 6 local unpack = table.unpack or unpack; -- luacheck: ignore 113/unpack |
7 local pack = require "util.table".pack; -- TODO table.pack in 5.2+ | |
8 local type = type; | 8 local type = type; |
9 local dump = require "util.serialization".new("debug"); | |
10 local num_type = math.type or function (n) | |
11 return n % 1 == 0 and n <= 9007199254740992 and n >= -9007199254740992 and "integer" or "float"; | |
12 end | |
13 | |
14 -- In Lua 5.3+ these formats throw an error if given a float | |
15 local expects_integer = { c = true, d = true, i = true, o = true, u = true, X = true, x = true, }; | |
9 | 16 |
10 local function format(formatstring, ...) | 17 local function format(formatstring, ...) |
11 local args, args_length = { ... }, select('#', ...); | 18 local args = pack(...); |
19 local args_length = args.n; | |
12 | 20 |
13 -- format specifier spec: | 21 -- format specifier spec: |
14 -- 1. Start: '%%' | 22 -- 1. Start: '%%' |
15 -- 2. Flags: '[%-%+ #0]' | 23 -- 2. Flags: '[%-%+ #0]' |
16 -- 3. Width: '%d?%d?' | 24 -- 3. Width: '%d?%d?' |
26 local i = 0; | 34 local i = 0; |
27 formatstring = formatstring:gsub("%%[^cdiouxXaAeEfgGqs%%]*[cdiouxXaAeEfgGqs%%]", function(spec) | 35 formatstring = formatstring:gsub("%%[^cdiouxXaAeEfgGqs%%]*[cdiouxXaAeEfgGqs%%]", function(spec) |
28 if spec ~= "%%" then | 36 if spec ~= "%%" then |
29 i = i + 1; | 37 i = i + 1; |
30 local arg = args[i]; | 38 local arg = args[i]; |
31 if arg == nil then -- special handling for nil | |
32 arg = "<nil>" | |
33 args[i] = "<nil>"; | |
34 end | |
35 | 39 |
36 local option = spec:sub(-1); | 40 local option = spec:sub(-1); |
37 if option == "q" or option == "s" then -- arg should be string | 41 if arg == nil then |
42 args[i] = "nil"; | |
43 spec = "<%s>"; | |
44 elseif option == "q" then | |
45 args[i] = dump(arg); | |
46 spec = "%s"; | |
47 elseif option == "s" then | |
38 args[i] = tostring(arg); | 48 args[i] = tostring(arg); |
39 elseif type(arg) ~= "number" then -- arg isn't number as expected? | 49 elseif type(arg) ~= "number" then -- arg isn't number as expected? |
50 args[i] = tostring(arg); | |
51 spec = "[%s]"; | |
52 elseif expects_integer[option] and num_type(arg) ~= "integer" then | |
40 args[i] = tostring(arg); | 53 args[i] = tostring(arg); |
41 spec = "[%s]"; | 54 spec = "[%s]"; |
42 end | 55 end |
43 end | 56 end |
44 return spec; | 57 return spec; |