Comparison

util/format.lua @ 12033:161f8268c4b3

util.format: Also handle the %p format added in Lua 5.4
author Kim Alvefur <zash@zash.se>
date Sat, 11 Dec 2021 13:39:58 +0100
parent 12032:3db09eb4c43b
child 12035:dc7ab05005e8
comparison
equal deleted inserted replaced
12032:3db09eb4c43b 12033:161f8268c4b3
27 ["\021"] = "\226\144\149", ["\022"] = "\226\144\150", ["\023"] = "\226\144\151", 27 ["\021"] = "\226\144\149", ["\022"] = "\226\144\150", ["\023"] = "\226\144\151",
28 ["\024"] = "\226\144\152", ["\025"] = "\226\144\153", ["\026"] = "\226\144\154", 28 ["\024"] = "\226\144\152", ["\025"] = "\226\144\153", ["\026"] = "\226\144\154",
29 ["\027"] = "\226\144\155", ["\028"] = "\226\144\156", ["\029"] = "\226\144\157", 29 ["\027"] = "\226\144\155", ["\028"] = "\226\144\156", ["\029"] = "\226\144\157",
30 ["\030"] = "\226\144\158", ["\031"] = "\226\144\159", ["\127"] = "\226\144\161", 30 ["\030"] = "\226\144\158", ["\031"] = "\226\144\159", ["\127"] = "\226\144\161",
31 }; 31 };
32 local supports_p = pcall(string.format, "%p", "");
32 33
33 local function format(formatstring, ...) 34 local function format(formatstring, ...)
34 local args = pack(...); 35 local args = pack(...);
35 local args_length = args.n; 36 local args_length = args.n;
36 37
42 -- 5. Option: '[cdiouxXaAeEfgGqs%%]' 43 -- 5. Option: '[cdiouxXaAeEfgGqs%%]'
43 -- 44 --
44 -- 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. 45 -- 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.
45 -- This function does not accept string values containing embedded zeros, except as arguments to the q option. 46 -- This function does not accept string values containing embedded zeros, except as arguments to the q option.
46 -- a and A are only in Lua 5.2+ 47 -- a and A are only in Lua 5.2+
48 -- Lua 5.4 adds a p format that produces a pointer
47 49
48 50
49 -- process each format specifier 51 -- process each format specifier
50 local i = 0; 52 local i = 0;
51 formatstring = formatstring:gsub("%%[^cdiouxXaAeEfgGqs%%]*[cdiouxXaAeEfgGqs%%]", function(spec) 53 formatstring = formatstring:gsub("%%[^cdiouxXaAeEfgGpqs%%]*[cdiouxXaAeEfgGpqs%%]", function(spec)
52 if spec == "%%" then return end 54 if spec == "%%" then return end
53 i = i + 1; 55 i = i + 1;
54 local arg = args[i]; 56 local arg = args[i];
55 57
56 if arg == nil then 58 if arg == nil then
64 if option == "s" and t == "string" and not arg:find("[%z\1-\31\128-\255]") then 66 if option == "s" and t == "string" and not arg:find("[%z\1-\31\128-\255]") then
65 -- No UTF-8 or control characters, assumed to be the common case. 67 -- No UTF-8 or control characters, assumed to be the common case.
66 return 68 return
67 end 69 end
68 70
69 if option ~= "s" and option ~= "q" then 71 if option ~= "s" and option ~= "q" and option ~= "p" then
70 -- all other options expect numbers 72 -- all other options expect numbers
71 if t ~= "number" then 73 if t ~= "number" then
72 -- arg isn't number as expected? 74 -- arg isn't number as expected?
73 arg = tostring(arg); 75 arg = tostring(arg);
74 option = "s"; 76 option = "s";
80 else 82 else
81 return -- acceptable number 83 return -- acceptable number
82 end 84 end
83 end 85 end
84 86
85 if t == "string" then 87
88 if option == "p" and not supports_p then
89 arg = tostring(arg);
90 option = "s";
91 spec = "[%s]";
92 t = "string";
93 end
94
95 if t == "string" and option ~= "p" then
86 if not valid_utf8(arg) then 96 if not valid_utf8(arg) then
87 option = "q"; 97 option = "q";
88 else 98 else
89 args[i] = arg:gsub("[%z\1-\8\11-\31\127]", control_symbols):gsub("\n\t?", "\n\t"); 99 args[i] = arg:gsub("[%z\1-\8\11-\31\127]", control_symbols):gsub("\n\t?", "\n\t");
90 return spec; 100 return spec;
92 end 102 end
93 103
94 if option == "q" then 104 if option == "q" then
95 args[i] = dump(arg); 105 args[i] = dump(arg);
96 return "%s"; 106 return "%s";
107 end
108
109 if option == "p" and (t == "boolean" or t == "number") then
110 args[i] = tostring(arg);
111 return "[%s]";
97 end 112 end
98 end); 113 end);
99 114
100 -- process extra args 115 -- process extra args
101 while i < args_length do 116 while i < args_length do