From 8d8d8c3817988a50ed1e058e73b247ce0a8c3616 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Wed, 11 May 2016 16:17:49 +0200 Subject: erts: Add enif_snprintf * Add the capability to format erlang terms to a char buffer in nifs. * Bump NIF version to 2.11 --- erts/emulator/beam/erl_nif.c | 10 ++++++++++ erts/emulator/beam/erl_nif.h | 3 ++- erts/emulator/beam/erl_nif_api_funcs.h | 2 ++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/erts/emulator/beam/erl_nif.c b/erts/emulator/beam/erl_nif.c index a695a028ba..fa20ce3c86 100644 --- a/erts/emulator/beam/erl_nif.c +++ b/erts/emulator/beam/erl_nif.c @@ -1603,6 +1603,16 @@ int enif_fprintf(void* filep, const char* format, ...) return ret; } +int enif_snprintf(char *buffer, size_t size, const char* format, ...) +{ + int ret; + va_list arglist; + va_start(arglist, format); + ret = erts_vsnprintf(buffer, size, format, arglist); + va_end(arglist); + return ret; +} + /*********************************************************** ** Memory managed (GC'ed) "resource" objects ** ***********************************************************/ diff --git a/erts/emulator/beam/erl_nif.h b/erts/emulator/beam/erl_nif.h index 3964f7f679..468f5cf5ec 100644 --- a/erts/emulator/beam/erl_nif.h +++ b/erts/emulator/beam/erl_nif.h @@ -50,9 +50,10 @@ ** 2.8: 18.0 add enif_has_pending_exception ** 2.9: 18.2 enif_getenv ** 2.10: Time API +** 2.11: 19.0 enif_snprintf */ #define ERL_NIF_MAJOR_VERSION 2 -#define ERL_NIF_MINOR_VERSION 10 +#define ERL_NIF_MINOR_VERSION 11 /* * The emulator will refuse to load a nif-lib with a major version diff --git a/erts/emulator/beam/erl_nif_api_funcs.h b/erts/emulator/beam/erl_nif_api_funcs.h index a5acd86551..c7389b1626 100644 --- a/erts/emulator/beam/erl_nif_api_funcs.h +++ b/erts/emulator/beam/erl_nif_api_funcs.h @@ -172,6 +172,7 @@ ERL_NIF_API_FUNC_DECL(int, enif_get_local_port, (ErlNifEnv* env, ERL_NIF_TERM, E ERL_NIF_API_FUNC_DECL(int, enif_term_to_binary, (ErlNifEnv *env, ERL_NIF_TERM term, ErlNifBinary *bin)); ERL_NIF_API_FUNC_DECL(size_t, enif_binary_to_term, (ErlNifEnv *env, const unsigned char* data, size_t sz, ERL_NIF_TERM *term, unsigned int opts)); ERL_NIF_API_FUNC_DECL(int, enif_port_command, (ErlNifEnv *env, const ErlNifPort* to_port, ErlNifEnv *msg_env, ERL_NIF_TERM msg)); +ERL_NIF_API_FUNC_DECL(int,enif_snprintf,(char * buffer, size_t size, const char *format, ...)); /* ** ADD NEW ENTRIES HERE (before this comment) !!! @@ -336,6 +337,7 @@ ERL_NIF_API_FUNC_DECL(int,enif_is_on_dirty_scheduler,(ErlNifEnv*)); # define enif_term_to_binary ERL_NIF_API_FUNC_MACRO(enif_term_to_binary) # define enif_binary_to_term ERL_NIF_API_FUNC_MACRO(enif_binary_to_term) # define enif_port_command ERL_NIF_API_FUNC_MACRO(enif_port_command) +# define enif_snprintf ERL_NIF_API_FUNC_MACRO(enif_snprintf) /* ** ADD NEW ENTRIES HERE (before this comment) -- cgit v1.2.3 From d3cde2d80d1cbcbbb70e4b8057a4f3772b7fa97f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Wed, 11 May 2016 17:49:45 +0200 Subject: erts: Add tests for enif_snprintf --- erts/emulator/test/nif_SUITE.erl | 17 ++++++++++++++--- erts/emulator/test/nif_SUITE_data/nif_SUITE.c | 20 +++++++++++++++++++- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/erts/emulator/test/nif_SUITE.erl b/erts/emulator/test/nif_SUITE.erl index a7767132ee..e764071415 100644 --- a/erts/emulator/test/nif_SUITE.erl +++ b/erts/emulator/test/nif_SUITE.erl @@ -46,7 +46,8 @@ nif_now_time/1, nif_cpu_time/1, nif_unique_integer/1, nif_is_process_alive/1, nif_is_port_alive/1, nif_term_to_binary/1, nif_binary_to_term/1, - nif_port_command/1 + nif_port_command/1, + nif_snprintf/1 ]). -export([many_args_100/100]). @@ -81,8 +82,8 @@ all() -> nif_now_time, nif_cpu_time, nif_unique_integer, nif_is_process_alive, nif_is_port_alive, nif_term_to_binary, nif_binary_to_term, - nif_port_command - ]. + nif_port_command, + nif_snprintf]. init_per_testcase(_Case, Config) -> Config. @@ -2024,9 +2025,18 @@ nif_port_command(Config) -> port_close(Port), {'EXIT', {badarg, _}} = (catch port_command_nif(Port, "hello\n")), + ok. +nif_snprintf(Config) -> + ensure_lib_loaded(Config), + <<"ok",0>> = format_term_nif(3,ok), + <<"o",0>> = format_term_nif(2,ok), + <<"\"hello world\"",0>> = format_term_nif(14,"hello world"), + <<"{{hello,world,-33},3.14",_/binary>> = format_term_nif(50,{{hello,world, -33}, 3.14, self()}), + <<"{{hello,world,-33},",0>> = format_term_nif(20,{{hello,world, -33}, 3.14, self()}), ok. + %% The NIFs: lib_version() -> undefined. call_history() -> ?nif_stub. @@ -2091,6 +2101,7 @@ is_port_alive_nif(_) -> ?nif_stub. term_to_binary_nif(_, _) -> ?nif_stub. binary_to_term_nif(_, _, _) -> ?nif_stub. port_command_nif(_, _) -> ?nif_stub. +format_term_nif(_,_) -> ?nif_stub. %% maps is_map_nif(_) -> ?nif_stub. diff --git a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c index 11e5dab58e..951b6959a8 100644 --- a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c +++ b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c @@ -2109,6 +2109,23 @@ static ERL_NIF_TERM port_command(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar return atom_true; } +static ERL_NIF_TERM format_term(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + ErlNifBinary obin; + unsigned int size; + + if (!enif_get_uint(env, argv[0], &size)) + return enif_make_badarg(env); + if (!enif_alloc_binary(size,&obin)) + return enif_make_badarg(env); + + if (enif_snprintf((char*)obin.data, (size_t)size, "%T", argv[1]) < 0) + return atom_false; + + return enif_make_binary(env,&obin); +} + + static ErlNifFunc nif_funcs[] = { {"lib_version", 0, lib_version}, @@ -2190,7 +2207,8 @@ static ErlNifFunc nif_funcs[] = {"is_port_alive_nif", 1, is_port_alive}, {"term_to_binary_nif", 2, term_to_binary}, {"binary_to_term_nif", 3, binary_to_term}, - {"port_command_nif", 2, port_command} + {"port_command_nif", 2, port_command}, + {"format_term_nif", 2, format_term} }; ERL_NIF_INIT(nif_SUITE,nif_funcs,load,reload,upgrade,unload) -- cgit v1.2.3 From c324aab53c00cfe2d0809bf25fed14a78ccf3ac2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Wed, 11 May 2016 17:59:06 +0200 Subject: erts: Document enif_snprintf --- erts/doc/src/erl_nif.xml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/erts/doc/src/erl_nif.xml b/erts/doc/src/erl_nif.xml index 7546f7ef81..d13302fa54 100644 --- a/erts/doc/src/erl_nif.xml +++ b/erts/doc/src/erl_nif.xml @@ -1653,6 +1653,15 @@ enif_map_iterator_destroy(env, &iter);

Get the byte size of a resource object obj obtained by enif_alloc_resource.

+ + intenif_snprintf(char *str, size_t size, const char *format, ...) + Format strings and Erlang terms + +

Similar to snprintf but this format string also accepts "%T" which formats Erlang terms. +

+
+
+ voidenif_system_info(ErlNifSysInfo *sys_info_ptr, size_t size) Get information about the Erlang runtime system -- cgit v1.2.3 From 88095fc0adb871671ff9763bd5868d7c0c0ac350 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Wed, 11 May 2016 18:18:26 +0200 Subject: runtime_tools: Change erts_snprintf to enif_snprintf --- lib/runtime_tools/c_src/dyntrace.c | 20 ++++++++++---------- lib/runtime_tools/c_src/dyntrace_lttng.h | 6 +++--- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/lib/runtime_tools/c_src/dyntrace.c b/lib/runtime_tools/c_src/dyntrace.c index 0178d95efb..e7a4a73373 100644 --- a/lib/runtime_tools/c_src/dyntrace.c +++ b/lib/runtime_tools/c_src/dyntrace.c @@ -433,7 +433,7 @@ static ERL_NIF_TERM trace_call(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv char class[LTTNG_BUFFER_SZ]; enif_get_tuple(env, argv[4], &arity, &tuple); - erts_snprintf(class, LTTNG_BUFFER_SZ, "%T", tuple[0]); + enif_snprintf(class, LTTNG_BUFFER_SZ, "%T", tuple[0]); if (enif_get_tuple(env, argv[3], &arity, &tuple)) { enif_get_uint(env, tuple[2], &len); @@ -465,7 +465,7 @@ static ERL_NIF_TERM trace_send(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv char msg[LTTNG_BUFFER_SZ]; lttng_pid_to_str(argv[4], to); - erts_snprintf(msg, LTTNG_BUFFER_SZ, "%T", argv[3]); + enif_snprintf(msg, LTTNG_BUFFER_SZ, "%T", argv[3]); LTTNG3(message_send, pid, to, msg); } else if (argv[0] == atom_send_to_non_existing_process) { @@ -473,7 +473,7 @@ static ERL_NIF_TERM trace_send(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv char msg[LTTNG_BUFFER_SZ]; lttng_pid_to_str(argv[4], to); - erts_snprintf(msg, LTTNG_BUFFER_SZ, "%T", argv[3]); + enif_snprintf(msg, LTTNG_BUFFER_SZ, "%T", argv[3]); /* mark it as non existing ? */ LTTNG3(message_send, pid, to, msg); @@ -496,7 +496,7 @@ static ERL_NIF_TERM trace_receive(ErlNifEnv* env, int argc, const ERL_NIF_TERM a char msg[LTTNG_BUFFER_SZ]; lttng_pid_to_str(argv[2], pid); - erts_snprintf(msg, LTTNG_BUFFER_SZ, "%T", argv[3]); + enif_snprintf(msg, LTTNG_BUFFER_SZ, "%T", argv[3]); LTTNG2(message_receive, pid, msg); } @@ -560,11 +560,11 @@ static ERL_NIF_TERM trace_procs(ErlNifEnv* env, int argc, const ERL_NIF_TERM arg /* register */ } else if (argv[0] == atom_register) { char name[LTTNG_BUFFER_SZ]; - erts_snprintf(name, LTTNG_BUFFER_SZ, "%T", argv[3]); + enif_snprintf(name, LTTNG_BUFFER_SZ, "%T", argv[3]); LTTNG3(process_register, pid, name, "register"); } else if (argv[0] == atom_unregister) { char name[LTTNG_BUFFER_SZ]; - erts_snprintf(name, LTTNG_BUFFER_SZ, "%T", argv[3]); + enif_snprintf(name, LTTNG_BUFFER_SZ, "%T", argv[3]); LTTNG3(process_register, pid, name, "unregister"); /* link */ } else if (argv[0] == atom_link) { @@ -582,7 +582,7 @@ static ERL_NIF_TERM trace_procs(ErlNifEnv* env, int argc, const ERL_NIF_TERM arg /* exit */ } else if (argv[0] == atom_exit) { char reason[LTTNG_BUFFER_SZ]; - erts_snprintf(reason, LTTNG_BUFFER_SZ, "%T", argv[3]); + enif_snprintf(reason, LTTNG_BUFFER_SZ, "%T", argv[3]); LTTNG2(process_exit, pid, reason); } return atom_ok; @@ -622,11 +622,11 @@ static ERL_NIF_TERM trace_ports(ErlNifEnv* env, int argc, const ERL_NIF_TERM arg lttng_decl_procbuf(pid); lttng_pid_to_str(argv[3], pid); - erts_snprintf(driver, LTTNG_BUFFER_SZ, "%T", argv[4]); + enif_snprintf(driver, LTTNG_BUFFER_SZ, "%T", argv[4]); LTTNG3(port_open, pid, driver, port); } else if (argv[0] == atom_closed) { char reason[LTTNG_BUFFER_SZ]; - erts_snprintf(reason, LTTNG_BUFFER_SZ, "%T", argv[3]); + enif_snprintf(reason, LTTNG_BUFFER_SZ, "%T", argv[3]); LTTNG2(port_exit, port, reason); /* link */ @@ -705,7 +705,7 @@ static ERL_NIF_TERM trace_running_ports(ErlNifEnv* env, int argc, const ERL_NIF_ lttng_decl_mfabuf(where); lttng_portid_to_str(argv[2], pid); - erts_snprintf(where, LTTNG_BUFFER_SZ, "%T", argv[3]); + enif_snprintf(where, LTTNG_BUFFER_SZ, "%T", argv[3]); /* running ports */ if (argv[0] == atom_in) { diff --git a/lib/runtime_tools/c_src/dyntrace_lttng.h b/lib/runtime_tools/c_src/dyntrace_lttng.h index 3550a1cab5..2a3224e191 100644 --- a/lib/runtime_tools/c_src/dyntrace_lttng.h +++ b/lib/runtime_tools/c_src/dyntrace_lttng.h @@ -59,10 +59,10 @@ char Name[LTTNG_MFA_BUFFER_SZ] #define lttng_pid_to_str(pid, name) \ - erts_snprintf(name, LTTNG_PROC_BUFFER_SZ, "%T", (pid)) + enif_snprintf(name, LTTNG_PROC_BUFFER_SZ, "%T", (pid)) #define lttng_portid_to_str(pid, name) \ - erts_snprintf(name, LTTNG_PORT_BUFFER_SZ, "%T", (pid)) + enif_snprintf(name, LTTNG_PORT_BUFFER_SZ, "%T", (pid)) #define lttng_proc_to_str(p, name) \ lttng_pid_to_str(((p) ? (p)->common.id : ERTS_INVALID_PID), name) @@ -71,7 +71,7 @@ lttng_portid_to_str(((p) ? (p)->common.id : ERTS_INVALID_PORT), name) #define lttng_mfa_to_str(m,f,a, Name) \ - erts_snprintf(Name, LTTNG_MFA_BUFFER_SZ, "%T:%T/%lu", (Eterm)(m), (Eterm)(f), (Uint)(a)) + enif_snprintf(Name, LTTNG_MFA_BUFFER_SZ, "%T:%T/%lu", (Eterm)(m), (Eterm)(f), (Uint)(a)) /* Process scheduling */ -- cgit v1.2.3