util/format.lua
author Kim Alvefur <zash@zash.se>
Sat, 14 Dec 2019 22:47:41 +0100
changeset 10507 e25a1a9a6e7e
parent 10039 386f085820e6
child 11642 5f4a657136bc
permissions -rw-r--r--
util.stanza: Accept util.error object to error_reply If we're moving towards util.error as the standard error container then this makes sense. This may allow for future extensibility without needing a lot of optional arguments.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
8228
70cb72f46a3b util.format: A string.format wrapper that gracefully handles invalid arguments
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
     1
--
70cb72f46a3b util.format: A string.format wrapper that gracefully handles invalid arguments
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
     2
-- A string.format wrapper that gracefully handles invalid arguments
70cb72f46a3b util.format: A string.format wrapper that gracefully handles invalid arguments
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
     3
--
70cb72f46a3b util.format: A string.format wrapper that gracefully handles invalid arguments
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
     4
70cb72f46a3b util.format: A string.format wrapper that gracefully handles invalid arguments
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
     5
local tostring = tostring;
8420
e88db5668cfb util.format: Import unpack from table lib in Lua 5.2+
Kim Alvefur <zash@zash.se>
parents: 8386
diff changeset
     6
local unpack = table.unpack or unpack; -- luacheck: ignore 113/unpack
9691
8c92ef4270c9 util.format: Use pack from util.table
Kim Alvefur <zash@zash.se>
parents: 9660
diff changeset
     7
local pack = require "util.table".pack; -- TODO table.pack in 5.2+
8228
70cb72f46a3b util.format: A string.format wrapper that gracefully handles invalid arguments
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
     8
local type = type;
9697
6ed0d6224d64 util.format: Serialize values for the %q format
Kim Alvefur <zash@zash.se>
parents: 9691
diff changeset
     9
local dump = require "util.serialization".new("debug");
10039
386f085820e6 util.format: Handle integer formats the same way on Lua versions without integer support
Kim Alvefur <zash@zash.se>
parents: 10038
diff changeset
    10
local num_type = math.type or function (n)
386f085820e6 util.format: Handle integer formats the same way on Lua versions without integer support
Kim Alvefur <zash@zash.se>
parents: 10038
diff changeset
    11
	return n % 1 == 0 and n <= 9007199254740992 and n >= -9007199254740992 and "integer" or "float";
386f085820e6 util.format: Handle integer formats the same way on Lua versions without integer support
Kim Alvefur <zash@zash.se>
parents: 10038
diff changeset
    12
end
10038
4fca92d60040 util.format: Handle formats expecting an integer in Lua 5.3+ (fixes #1371)
Kim Alvefur <zash@zash.se>
parents: 9697
diff changeset
    13
10039
386f085820e6 util.format: Handle integer formats the same way on Lua versions without integer support
Kim Alvefur <zash@zash.se>
parents: 10038
diff changeset
    14
-- In Lua 5.3+ these formats throw an error if given a float
386f085820e6 util.format: Handle integer formats the same way on Lua versions without integer support
Kim Alvefur <zash@zash.se>
parents: 10038
diff changeset
    15
local expects_integer = { c = true, d = true, i = true, o = true, u = true, X = true, x = true, };
8228
70cb72f46a3b util.format: A string.format wrapper that gracefully handles invalid arguments
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    16
8385
e5d00bf4a4d5 util: Various minor changes to please [luacheck]
Kim Alvefur <zash@zash.se>
parents: 8228
diff changeset
    17
local function format(formatstring, ...)
9691
8c92ef4270c9 util.format: Use pack from util.table
Kim Alvefur <zash@zash.se>
parents: 9660
diff changeset
    18
	local args = pack(...);
8c92ef4270c9 util.format: Use pack from util.table
Kim Alvefur <zash@zash.se>
parents: 9660
diff changeset
    19
	local args_length = args.n;
8228
70cb72f46a3b util.format: A string.format wrapper that gracefully handles invalid arguments
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    20
70cb72f46a3b util.format: A string.format wrapper that gracefully handles invalid arguments
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    21
	-- format specifier spec:
70cb72f46a3b util.format: A string.format wrapper that gracefully handles invalid arguments
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    22
	-- 1. Start: '%%'
70cb72f46a3b util.format: A string.format wrapper that gracefully handles invalid arguments
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    23
	-- 2. Flags: '[%-%+ #0]'
70cb72f46a3b util.format: A string.format wrapper that gracefully handles invalid arguments
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    24
	-- 3. Width: '%d?%d?'
70cb72f46a3b util.format: A string.format wrapper that gracefully handles invalid arguments
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    25
	-- 4. Precision: '%.?%d?%d?'
70cb72f46a3b util.format: A string.format wrapper that gracefully handles invalid arguments
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    26
	-- 5. Option: '[cdiouxXaAeEfgGqs%%]'
70cb72f46a3b util.format: A string.format wrapper that gracefully handles invalid arguments
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    27
	--
70cb72f46a3b util.format: A string.format wrapper that gracefully handles invalid arguments
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    28
	-- 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.
70cb72f46a3b util.format: A string.format wrapper that gracefully handles invalid arguments
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    29
	-- This function does not accept string values containing embedded zeros, except as arguments to the q option.
70cb72f46a3b util.format: A string.format wrapper that gracefully handles invalid arguments
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    30
	-- a and A are only in Lua 5.2+
70cb72f46a3b util.format: A string.format wrapper that gracefully handles invalid arguments
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    31
70cb72f46a3b util.format: A string.format wrapper that gracefully handles invalid arguments
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    32
70cb72f46a3b util.format: A string.format wrapper that gracefully handles invalid arguments
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    33
	-- process each format specifier
70cb72f46a3b util.format: A string.format wrapper that gracefully handles invalid arguments
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    34
	local i = 0;
8385
e5d00bf4a4d5 util: Various minor changes to please [luacheck]
Kim Alvefur <zash@zash.se>
parents: 8228
diff changeset
    35
	formatstring = formatstring:gsub("%%[^cdiouxXaAeEfgGqs%%]*[cdiouxXaAeEfgGqs%%]", function(spec)
8228
70cb72f46a3b util.format: A string.format wrapper that gracefully handles invalid arguments
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    36
		if spec ~= "%%" then
70cb72f46a3b util.format: A string.format wrapper that gracefully handles invalid arguments
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    37
			i = i + 1;
70cb72f46a3b util.format: A string.format wrapper that gracefully handles invalid arguments
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    38
			local arg = args[i];
70cb72f46a3b util.format: A string.format wrapper that gracefully handles invalid arguments
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    39
70cb72f46a3b util.format: A string.format wrapper that gracefully handles invalid arguments
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    40
			local option = spec:sub(-1);
9660
3da6cc927ee6 util.format: Tweak how nil values are handled
Kim Alvefur <zash@zash.se>
parents: 8420
diff changeset
    41
			if arg == nil then
3da6cc927ee6 util.format: Tweak how nil values are handled
Kim Alvefur <zash@zash.se>
parents: 8420
diff changeset
    42
				args[i] = "nil";
3da6cc927ee6 util.format: Tweak how nil values are handled
Kim Alvefur <zash@zash.se>
parents: 8420
diff changeset
    43
				spec = "<%s>";
9697
6ed0d6224d64 util.format: Serialize values for the %q format
Kim Alvefur <zash@zash.se>
parents: 9691
diff changeset
    44
			elseif option == "q" then
6ed0d6224d64 util.format: Serialize values for the %q format
Kim Alvefur <zash@zash.se>
parents: 9691
diff changeset
    45
				args[i] = dump(arg);
6ed0d6224d64 util.format: Serialize values for the %q format
Kim Alvefur <zash@zash.se>
parents: 9691
diff changeset
    46
				spec = "%s";
6ed0d6224d64 util.format: Serialize values for the %q format
Kim Alvefur <zash@zash.se>
parents: 9691
diff changeset
    47
			elseif option == "s" then
8228
70cb72f46a3b util.format: A string.format wrapper that gracefully handles invalid arguments
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    48
				args[i] = tostring(arg);
70cb72f46a3b util.format: A string.format wrapper that gracefully handles invalid arguments
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    49
			elseif type(arg) ~= "number" then -- arg isn't number as expected?
70cb72f46a3b util.format: A string.format wrapper that gracefully handles invalid arguments
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    50
				args[i] = tostring(arg);
70cb72f46a3b util.format: A string.format wrapper that gracefully handles invalid arguments
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    51
				spec = "[%s]";
10038
4fca92d60040 util.format: Handle formats expecting an integer in Lua 5.3+ (fixes #1371)
Kim Alvefur <zash@zash.se>
parents: 9697
diff changeset
    52
			elseif expects_integer[option] and num_type(arg) ~= "integer" then
4fca92d60040 util.format: Handle formats expecting an integer in Lua 5.3+ (fixes #1371)
Kim Alvefur <zash@zash.se>
parents: 9697
diff changeset
    53
				args[i] = tostring(arg);
4fca92d60040 util.format: Handle formats expecting an integer in Lua 5.3+ (fixes #1371)
Kim Alvefur <zash@zash.se>
parents: 9697
diff changeset
    54
				spec = "[%s]";
8228
70cb72f46a3b util.format: A string.format wrapper that gracefully handles invalid arguments
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    55
			end
70cb72f46a3b util.format: A string.format wrapper that gracefully handles invalid arguments
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    56
		end
70cb72f46a3b util.format: A string.format wrapper that gracefully handles invalid arguments
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    57
		return spec;
70cb72f46a3b util.format: A string.format wrapper that gracefully handles invalid arguments
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    58
	end);
70cb72f46a3b util.format: A string.format wrapper that gracefully handles invalid arguments
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    59
70cb72f46a3b util.format: A string.format wrapper that gracefully handles invalid arguments
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    60
	-- process extra args
70cb72f46a3b util.format: A string.format wrapper that gracefully handles invalid arguments
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    61
	while i < args_length do
70cb72f46a3b util.format: A string.format wrapper that gracefully handles invalid arguments
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    62
		i = i + 1;
70cb72f46a3b util.format: A string.format wrapper that gracefully handles invalid arguments
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    63
		local arg = args[i];
70cb72f46a3b util.format: A string.format wrapper that gracefully handles invalid arguments
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    64
		if arg == nil then
70cb72f46a3b util.format: A string.format wrapper that gracefully handles invalid arguments
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    65
			args[i] = "<nil>";
70cb72f46a3b util.format: A string.format wrapper that gracefully handles invalid arguments
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    66
		else
70cb72f46a3b util.format: A string.format wrapper that gracefully handles invalid arguments
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    67
			args[i] = tostring(arg);
70cb72f46a3b util.format: A string.format wrapper that gracefully handles invalid arguments
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    68
		end
8385
e5d00bf4a4d5 util: Various minor changes to please [luacheck]
Kim Alvefur <zash@zash.se>
parents: 8228
diff changeset
    69
		formatstring = formatstring .. " [%s]"
8228
70cb72f46a3b util.format: A string.format wrapper that gracefully handles invalid arguments
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    70
	end
70cb72f46a3b util.format: A string.format wrapper that gracefully handles invalid arguments
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    71
8385
e5d00bf4a4d5 util: Various minor changes to please [luacheck]
Kim Alvefur <zash@zash.se>
parents: 8228
diff changeset
    72
	return formatstring:format(unpack(args));
8228
70cb72f46a3b util.format: A string.format wrapper that gracefully handles invalid arguments
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    73
end
70cb72f46a3b util.format: A string.format wrapper that gracefully handles invalid arguments
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    74
70cb72f46a3b util.format: A string.format wrapper that gracefully handles invalid arguments
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    75
return {
70cb72f46a3b util.format: A string.format wrapper that gracefully handles invalid arguments
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    76
	format = format;
70cb72f46a3b util.format: A string.format wrapper that gracefully handles invalid arguments
Waqas Hussain <waqas20@gmail.com>
parents:
diff changeset
    77
};