From dfebe439db76b5c9fd9b4e3877857e2449c8ad87 Mon Sep 17 00:00:00 2001 From: Roberto Ierusalimschy Date: Wed, 13 Mar 2019 14:04:01 -0300 Subject: [PATCH] New conversion specifier '%p' for 'string.format' The call 'string.format("%p", val)' gives a Lua equivalent to the C API function 'lua_topointer'. --- lstrlib.c | 5 +++++ manual/manual.of | 13 ++++++++++--- testes/strings.lua | 16 ++++++++++++++++ 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/lstrlib.c b/lstrlib.c index ab4258e5..6230cd0c 100644 --- a/lstrlib.c +++ b/lstrlib.c @@ -1185,6 +1185,11 @@ static int str_format (lua_State *L) { nb = l_sprintf(buff, MAX_ITEM, form, (LUAI_UACNUMBER)n); break; } + case 'p': { + const void *p = lua_topointer(L, arg); + nb = l_sprintf(buff, MAX_ITEM, form, p); + break; + } case 'q': { if (form[2] != '\0') /* modifiers? */ return luaL_error(L, "specifier '%%q' cannot have modifiers"); diff --git a/manual/manual.of b/manual/manual.of index 9c8ab033..2eb8773f 100644 --- a/manual/manual.of +++ b/manual/manual.of @@ -6751,8 +6751,7 @@ Returns a formatted version of its variable number of arguments following the description given in its first argument (which must be a string). The format string follows the same rules as the @ANSI{sprintf}. The only differences are that the conversion specifiers and modifiers -@T{*}, @id{h}, @id{L}, @id{l}, @id{n}, -and @id{p} are not supported +@T{*}, @id{h}, @id{L}, @id{l}, and @id{n} are not supported and that there is an extra specifier, @id{q}. The specifier @id{q} formats booleans, nil, numbers, and strings @@ -6791,6 +6790,14 @@ it is converted to one following the same rules of @Lid{tostring}. If the specifier has any modifier, the corresponding string argument should not contain @x{embedded zeros}. +The specifier @id{p} formats the pointer +returned by @Lid{lua_topointer}. +That gives a unique string identifier for tables, userdata, +threads, strings, and functions. +For other values (numbers, nil, booleans), +this specifier results in a string representing +the pointer @id{NULL}. + } @LibEntry{string.gmatch (s, pattern [, init])| @@ -8768,7 +8775,7 @@ address space.) } @item{ -The constant @Lid{LUA_ERRGCMM} was removed. +The constant @id{LUA_ERRGCMM} was removed. Errors in finalizers are never propagated; instead, they generate a warning. } diff --git a/testes/strings.lua b/testes/strings.lua index da53a87e..8bcbb391 100644 --- a/testes/strings.lua +++ b/testes/strings.lua @@ -153,6 +153,22 @@ else -- compatible coercion assert(tostring(-1203 + 0.0) == "-1203") end +do -- tests for '%p' format + -- not much to test, as C does not specify what '%p' does. + -- ("The value of the pointer is converted to a sequence of printing + -- characters, in an implementation-defined manner.") + local null = string.format("%p", nil) + assert(string.format("%p", {}) ~= null) + assert(string.format("%p", 4) == null) + assert(string.format("%p", print) ~= null) + assert(string.format("%p", coroutine.running()) ~= null) + assert(string.format("%p", {}) ~= string.format("%p", {})) + assert(string.format("%p", string.rep("a", 10)) == + string.format("%p", string.rep("a", 10))) -- short strings + assert(string.format("%p", string.rep("a", 300)) ~= + string.format("%p", string.rep("a", 300))) -- long strings + assert(#string.format("%90p", {}) == 90) +end x = '"ílo"\n\\' assert(string.format('%q%s', x, x) == '"\\"ílo\\"\\\n\\\\""ílo"\n\\')