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;