diff options
-rw-r--r-- | erts/doc/src/erl_nif.xml | 44 | ||||
-rw-r--r-- | erts/emulator/beam/erl_nif.c | 54 | ||||
-rw-r--r-- | erts/emulator/beam/erl_nif_api_funcs.h | 14 | ||||
-rw-r--r-- | erts/emulator/test/nif_SUITE.erl | 35 | ||||
-rw-r--r-- | erts/emulator/test/nif_SUITE_data/nif_SUITE.c | 106 |
5 files changed, 241 insertions, 12 deletions
diff --git a/erts/doc/src/erl_nif.xml b/erts/doc/src/erl_nif.xml index 5ec844e2ad..03bd42d3b1 100644 --- a/erts/doc/src/erl_nif.xml +++ b/erts/doc/src/erl_nif.xml @@ -477,6 +477,12 @@ typedef enum { <c>term</c> is not an atom with maximum length of <c>size-1</c>.</p></desc> </func> + <func><name><ret>int</ret><nametext>enif_get_atom_length(ErlNifEnv* env, ERL_NIF_TERM term, unsigned* len)</nametext></name> + <fsummary>Get the length of atom <c>term</c>.</fsummary> + <desc><p>Set <c>*len</c> to the length (number of bytes excluding + terminating null character) of <c>term</c> or return false if + <c>term</c> is not an atom.</p></desc> + </func> <func><name><ret>int</ret><nametext>enif_get_double(ErlNifEnv* env, ERL_NIF_TERM term, double* dp)</nametext></name> <fsummary>Read a floating-point number term.</fsummary> <desc><p>Set <c>*dp</c> to the floating point value of @@ -494,6 +500,11 @@ typedef enum { <c>list</c> or return false if <c>list</c> is not a non-empty list.</p></desc> </func> + <func><name><ret>int</ret><nametext>enif_get_list_length(ErlNifEnv* env, ERL_NIF_TERM term, unsigned* len)</nametext></name> + <fsummary>Get the length of list <c>term</c>.</fsummary> + <desc><p>Set <c>*len</c> to the length of <c>term</c> or return + false if <c>term</c> is not a list.</p></desc> + </func> <func><name><ret>int</ret><nametext>enif_get_long(ErlNifEnv* env, ERL_NIF_TERM term, long int* ip)</nametext></name> <fsummary>Read an long integer term.</fsummary> <desc><p>Set <c>*ip</c> to the long integer value of @@ -597,10 +608,24 @@ typedef enum { <fsummary>Determine if a term is a reference</fsummary> <desc><p>Return true if <c>term</c> is a reference.</p></desc> </func> + <func><name><ret>int</ret><nametext>enif_is_tuple(ErlNifEnv* env, ERL_NIF_TERM term)</nametext></name> + <fsummary>Determine if a term is a tuple</fsummary> + <desc><p>Return true if <c>term</c> is a tuple.</p></desc> + </func> + <func><name><ret>int</ret><nametext>enif_is_list(ErlNifEnv* env, ERL_NIF_TERM term)</nametext></name> + <fsummary>Determine if a term is a list</fsummary> + <desc><p>Return true if <c>term</c> is a list.</p></desc> + </func> <func><name><ret>ERL_NIF_TERM</ret><nametext>enif_make_atom(ErlNifEnv* env, const char* name)</nametext></name> <fsummary>Create an atom term</fsummary> - <desc><p>Create an atom term from the C-string <c>name</c>. Unlike other terms, atom - terms may be saved and used between NIF calls.</p></desc> + <desc><p>Create an atom term from the null-terminated C-string <c>name</c>. + Unlike other terms, atom terms may be saved and used between NIF calls.</p></desc> + </func> + <func><name><ret>ERL_NIF_TERM</ret><nametext>enif_make_atom_len(ErlNifEnv* env, const char* name, size_t len)</nametext></name> + <fsummary>Create an atom term</fsummary> + <desc><p>Create an atom term from the string <c>name</c> with length <c>len</c>. + Null-characters are treated as any other characters. + Unlike other terms, atom terms may be saved and used between NIF calls.</p></desc> </func> <func><name><ret>ERL_NIF_TERM</ret><nametext>enif_make_badarg(ErlNifEnv* env)</nametext></name> <fsummary>Make a badarg exception.</fsummary> @@ -620,10 +645,17 @@ typedef enum { <func><name><ret>int</ret><nametext>enif_make_existing_atom(ErlNifEnv* env, const char* name, ERL_NIF_TERM* atom)</nametext></name> <fsummary>Create an existing atom term</fsummary> <desc><p>Try to create the term of an already existing atom from - the C-string <c>name</c>. If the atom already exist store the + the null-terminated C-string <c>name</c>. If the atom already exists store the term in <c>*atom</c> and return true, otherwise return false.</p></desc> </func> + <func><name><ret>int</ret><nametext>enif_make_existing_atom_len(ErlNifEnv* env, const char* name, size_t len, ERL_NIF_TERM* atom)</nametext></name> + <fsummary>Create an existing atom term</fsummary> + <desc><p>Try to create the term of an already existing atom from the + string <c>name</c> with length <c>len</c>. Null-characters are treated + as any other characters. If the atom already exists store the term + in <c>*atom</c> and return true, otherwise return false.</p></desc> + </func> <func><name><ret>ERL_NIF_TERM</ret><nametext>enif_make_int(ErlNifEnv* env, int i)</nametext></name> <fsummary>Create an integer term</fsummary> <desc><p>Create an integer term.</p></desc> @@ -692,6 +724,12 @@ typedef enum { <desc><p>Create a list containing the characters of the null-terminated string <c>string</c> with encoding <seealso marker="#ErlNifCharEncoding">encoding</seealso>.</p></desc> </func> + <func><name><ret>ERL_NIF_TERM</ret><nametext>enif_make_string_len(ErlNifEnv* env, const char* string, size_t len, ErlNifCharEncoding encoding)</nametext></name> + <fsummary>Create a string.</fsummary> + <desc><p>Create a list containing the characters of the string <c>string</c> with + length <c>len</c> and encoding <seealso marker="#ErlNifCharEncoding">encoding</seealso>. + Null-characters are treated as any other characters.</p></desc> + </func> <func><name><ret>ERL_NIF_TERM</ret><nametext>enif_make_sub_binary(ErlNifEnv* env, ERL_NIF_TERM bin_term, unsigned pos, unsigned size)</nametext></name> <fsummary>Make a subbinary term.</fsummary> diff --git a/erts/emulator/beam/erl_nif.c b/erts/emulator/beam/erl_nif.c index cee4df72a2..7095ae03e7 100644 --- a/erts/emulator/beam/erl_nif.c +++ b/erts/emulator/beam/erl_nif.c @@ -248,6 +248,16 @@ int enif_is_ref(ErlNifEnv* env, ERL_NIF_TERM term) return is_ref(term); } +int enif_is_tuple(ErlNifEnv* env, ERL_NIF_TERM term) +{ + return is_tuple(term); +} + +int enif_is_list(ErlNifEnv* env, ERL_NIF_TERM term) +{ + return is_list(term) || is_nil(term); +} + static void aligned_binary_dtor(struct enif_tmp_obj_t* obj) { erts_free_aligned_binary_bytes_extra((byte*)obj,ERTS_ALC_T_TMP); @@ -591,6 +601,15 @@ int enif_get_double(ErlNifEnv* env, Eterm term, double* dp) return 1; } +int enif_get_atom_length(ErlNifEnv* env, Eterm atom, unsigned* len) +{ + Atom* ap; + if (is_not_atom(atom)) return 0; + ap = atom_tab(atom_val(atom)); + *len = ap->len; + return 1; +} + int enif_get_list_cell(ErlNifEnv* env, Eterm term, Eterm* head, Eterm* tail) { Eterm* val; @@ -601,6 +620,13 @@ int enif_get_list_cell(ErlNifEnv* env, Eterm term, Eterm* head, Eterm* tail) return 1; } +int enif_get_list_length(ErlNifEnv* env, Eterm term, unsigned* len) +{ + if (is_not_list(term) && is_not_nil(term)) return 0; + *len = list_length(term); + return 1; +} + ERL_NIF_TERM enif_make_int(ErlNifEnv* env, int i) { #if SIZEOF_INT == ERTS_SIZEOF_ETERM @@ -640,12 +666,23 @@ ERL_NIF_TERM enif_make_double(ErlNifEnv* env, double d) ERL_NIF_TERM enif_make_atom(ErlNifEnv* env, const char* name) { - return am_atom_put(name, sys_strlen(name)); + return enif_make_atom_len(env, name, sys_strlen(name)); +} + +ERL_NIF_TERM enif_make_atom_len(ErlNifEnv* env, const char* name, size_t len) +{ + return am_atom_put(name, len); } int enif_make_existing_atom(ErlNifEnv* env, const char* name, ERL_NIF_TERM* atom) { - return erts_atom_get(name, sys_strlen(name), atom); + return enif_make_existing_atom_len(env, name, sys_strlen(name), atom); +} + +int enif_make_existing_atom_len(ErlNifEnv* env, const char* name, size_t len, + ERL_NIF_TERM* atom) +{ + return erts_atom_get(name, len, atom); } ERL_NIF_TERM enif_make_tuple(ErlNifEnv* env, unsigned cnt, ...) @@ -724,11 +761,16 @@ ERL_NIF_TERM enif_make_list_from_array(ErlNifEnv* env, const ERL_NIF_TERM arr[], ERL_NIF_TERM enif_make_string(ErlNifEnv* env, const char* string, ErlNifCharEncoding encoding) -{ - Sint n = sys_strlen(string); - Eterm* hp = alloc_heap(env,n*2); +{ + return enif_make_string_len(env, string, sys_strlen(string), encoding); +} + +ERL_NIF_TERM enif_make_string_len(ErlNifEnv* env, const char* string, + size_t len, ErlNifCharEncoding encoding) +{ + Eterm* hp = alloc_heap(env,len*2); ASSERT(encoding == ERL_NIF_LATIN1); - return erts_bld_string_n(&hp,NULL,string,n); + return erts_bld_string_n(&hp,NULL,string,len); } ERL_NIF_TERM enif_make_ref(ErlNifEnv* env) diff --git a/erts/emulator/beam/erl_nif_api_funcs.h b/erts/emulator/beam/erl_nif_api_funcs.h index fe8d2664e1..44bcca9ca4 100644 --- a/erts/emulator/beam/erl_nif_api_funcs.h +++ b/erts/emulator/beam/erl_nif_api_funcs.h @@ -106,6 +106,13 @@ ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_resource,(ErlNifEnv*, void* obj)); ERL_NIF_API_FUNC_DECL(int,enif_get_resource,(ErlNifEnv*, ERL_NIF_TERM term, ErlNifResourceType* type, void** objp)); ERL_NIF_API_FUNC_DECL(unsigned,enif_sizeof_resource,(ErlNifEnv*, void* obj)); ERL_NIF_API_FUNC_DECL(unsigned char*,enif_make_new_binary,(ErlNifEnv*,unsigned size,ERL_NIF_TERM* termp)); +ERL_NIF_API_FUNC_DECL(int,enif_is_list,(ErlNifEnv*, ERL_NIF_TERM term)); +ERL_NIF_API_FUNC_DECL(int,enif_is_tuple,(ErlNifEnv*, ERL_NIF_TERM term)); +ERL_NIF_API_FUNC_DECL(int,enif_get_atom_length,(ErlNifEnv*, ERL_NIF_TERM atom, unsigned* len)); +ERL_NIF_API_FUNC_DECL(int,enif_get_list_length,(ErlNifEnv* env, ERL_NIF_TERM term, unsigned* len)); +ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM, enif_make_atom_len,(ErlNifEnv* env, const char* name, size_t len)); +ERL_NIF_API_FUNC_DECL(int, enif_make_existing_atom_len,(ErlNifEnv* env, const char* name, size_t len, ERL_NIF_TERM* atom)); +ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_string_len,(ErlNifEnv* env, const char* string, size_t len, ErlNifCharEncoding)); /* ** Add last to keep compatibility on Windows!!! @@ -198,6 +205,13 @@ ERL_NIF_API_FUNC_DECL(unsigned char*,enif_make_new_binary,(ErlNifEnv*,unsigned s # define enif_get_resource ERL_NIF_API_FUNC_MACRO(enif_get_resource) # define enif_sizeof_resource ERL_NIF_API_FUNC_MACRO(enif_sizeof_resource) # define enif_make_new_binary ERL_NIF_API_FUNC_MACRO(enif_make_new_binary) +# define enif_is_list ERL_NIF_API_FUNC_MACRO(enif_is_list) +# define enif_is_tuple ERL_NIF_API_FUNC_MACRO(enif_is_tuple) +# define enif_get_atom_length ERL_NIF_API_FUNC_MACRO(enif_get_atom_length) +# define enif_get_list_length ERL_NIF_API_FUNC_MACRO(enif_get_list_length) +# define enif_make_atom_len ERL_NIF_API_FUNC_MACRO(enif_make_atom_len) +# define enif_make_existing_atom_len ERL_NIF_API_FUNC_MACRO(enif_make_existing_atom_len) +# define enif_make_string_len ERL_NIF_API_FUNC_MACRO(enif_make_string_len) #endif #ifndef enif_make_list1 diff --git a/erts/emulator/test/nif_SUITE.erl b/erts/emulator/test/nif_SUITE.erl index 522caec8f1..161e38c68a 100644 --- a/erts/emulator/test/nif_SUITE.erl +++ b/erts/emulator/test/nif_SUITE.erl @@ -28,7 +28,7 @@ -export([all/1, fin_per_testcase/2, basic/1, reload/1, upgrade/1, heap_frag/1, types/1, many_args/1, binaries/1, get_string/1, get_atom/1, api_macros/1, from_array/1, iolist_as_binary/1, resource/1, resource_takeover/1, - threading/1, neg/1]). + threading/1, neg/1, is_checks/1, get_length/1, make_atom/1, make_string/1]). -export([many_args_100/100]). -define(nif_stub,nif_stub_error(?LINE)). @@ -36,7 +36,8 @@ all(suite) -> [basic, reload, upgrade, heap_frag, types, many_args, binaries, get_string, get_atom, api_macros, from_array, iolist_as_binary, resource, - resource_takeover, threading, neg]. + resource_takeover, threading, neg, is_checks, get_length, make_atom, + make_string]. %%init_per_testcase(_Case, Config) -> %% ?line Dog = ?t:timetrap(?t:seconds(60*60*24)), @@ -759,7 +760,17 @@ neg(Config) when is_list(Config) -> ?line verify_tmpmem(TmpMem), ?line ok. +is_checks(doc) -> ["Test all enif_is functions"]; +is_checks(Config) when is_list(Config) -> + ?line ensure_lib_loaded(Config, 1), + ?line ok = check_is(hejsan, <<19,98>>, make_ref(), ok, fun() -> ok end, + self(), hd(erlang:ports()), [], [1,9,9,8], + {hejsan, "hejsan", [$h,"ejs",<<"an">>]}). +get_length(doc) -> ["Test all enif_get_length functions"]; +get_length(Config) when is_list(Config) -> + ?line ensure_lib_loaded(Config, 1), + ?line ok = length_test(hejsan, "hejsan", [], [], not_a_list). ensure_lib_loaded(Config) -> ensure_lib_loaded(Config, 1). @@ -773,6 +784,22 @@ ensure_lib_loaded(Config, Ver) -> ok end. +make_atom(Config) when is_list(Config) -> + ?line ensure_lib_loaded(Config, 1), + An0Atom = an0atom, + An0Atom0 = 'an\000atom\000', + ?line Atoms = make_atoms(), + ?line 7 = size(Atoms), + ?line Atoms = {An0Atom,An0Atom,An0Atom,An0Atom0,An0Atom,An0Atom,An0Atom0}. + +make_string(Config) when is_list(Config) -> + ?line ensure_lib_loaded(Config, 1), + ?line Strings = make_strings(), + ?line 4 = size(Strings), + A0String = "a0string", + A0String0 = [$a,0,$s,$t,$r,$i,$n,$g,0], + ?line Strings = {A0String,A0String,A0String,A0String0}. + tmpmem() -> case erlang:system_info({allocator,temp_alloc}) of false -> undefined; @@ -855,6 +882,10 @@ get_resource(_,_) -> ?nif_stub. release_resource(_) -> ?nif_stub. last_resource_dtor_call() -> ?nif_stub. make_new_resource(_,_) -> ?nif_stub. +check_is(_,_,_,_,_,_,_,_,_,_) -> ?nif_stub. +length_test(_,_,_,_,_) -> ?nif_stub. +make_atoms() -> ?nif_stub. +make_strings() -> ?nif_stub. nif_stub_error(Line) -> exit({nif_not_loaded,module,?MODULE,line,Line}). diff --git a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c index 3ad4f93374..73226a09cb 100644 --- a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c +++ b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c @@ -630,6 +630,106 @@ static ERL_NIF_TERM release_resource(ErlNifEnv* env, int argc, const ERL_NIF_TER return enif_make_atom(env,"ok"); } +/* + * argv[0] an atom + * argv[1] a binary + * argv[2] a ref + * argv[3] 'ok' + * argv[4] a fun + * argv[5] a pid + * argv[6] a port + * argv[7] an empty list + * argv[8] a non-empty list + * argv[9] a tuple + */ +static ERL_NIF_TERM check_is(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + ERL_NIF_TERM ok_atom = enif_make_atom(env, "ok"); + + if (!enif_is_atom(env, argv[0])) return enif_make_badarg(env); + if (!enif_is_binary(env, argv[1])) return enif_make_badarg(env); + if (!enif_is_ref(env, argv[2])) return enif_make_badarg(env); + if (!enif_is_identical(env, argv[3], ok_atom)) return enif_make_badarg(env); + if (!enif_is_fun(env, argv[4])) return enif_make_badarg(env); + if (!enif_is_pid(env, argv[5])) return enif_make_badarg(env); + if (!enif_is_port(env, argv[6])) return enif_make_badarg(env); + if (!enif_is_empty_list(env, argv[7])) return enif_make_badarg(env); + if (!enif_is_list(env, argv[7])) return enif_make_badarg(env); + if (!enif_is_list(env, argv[8])) return enif_make_badarg(env); + if (!enif_is_tuple(env, argv[9])) return enif_make_badarg(env); + + return ok_atom; +} + +/* + * argv[0] atom with length of 6 + * argv[1] list with length of 6 + * argv[2] empty list + * argv[3] not an atom + * argv[4] not a list + */ +static ERL_NIF_TERM length_test(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + unsigned len; + + if (!enif_get_atom_length(env, argv[0], &len) || len != 6) + return enif_make_badarg(env); + + if (!enif_get_list_length(env, argv[1], &len) || len != 6) + return enif_make_badarg(env); + + if (!enif_get_list_length(env, argv[2], &len) || len != 0) + return enif_make_badarg(env); + + if (enif_get_atom_length(env, argv[3], &len)) + return enif_make_badarg(env); + + if (enif_get_list_length(env, argv[4], &len)) + return enif_make_badarg(env); + + return enif_make_atom(env, "ok"); +} + +static ERL_NIF_TERM make_atoms(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + ERL_NIF_TERM arr[7]; + ERL_NIF_TERM existingatom0a, existingatom0b; + ERL_NIF_TERM existing0atom0; + const char * const an0atom = "an0atom"; + const char an0atom0[8] = {'a','n','\0','a','t','o','m',0}; + + arr[0] = enif_make_atom(env, "an0atom"); + arr[1] = enif_make_atom_len(env, "an0atom", 7); + arr[2] = enif_make_atom_len(env, an0atom, 7); + arr[3] = enif_make_atom_len(env, an0atom0, 8); + + if (!enif_make_existing_atom(env, "an0atom", &existingatom0a)) + return enif_make_atom(env, "error"); + arr[4] = existingatom0a; + + if (!enif_make_existing_atom_len(env, an0atom, 7, &existingatom0b)) + return enif_make_atom(env, "error"); + arr[5] = existingatom0b; + + if (!enif_make_existing_atom_len(env, an0atom0, 8, &existing0atom0)) + return enif_make_atom(env, "error"); + arr[6] = existing0atom0; + + return enif_make_tuple7(env, + arr[0],arr[1],arr[2],arr[3],arr[4],arr[5],arr[6]); +} + +static ERL_NIF_TERM make_strings(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + const char a0string[8] = {'a','0','s','t','r','i','n','g'}; + const char a0string0[9] = {'a','\0','s','t','r','i','n','g',0}; + + return enif_make_tuple4(env, + enif_make_string(env, "a0string", ERL_NIF_LATIN1), + enif_make_string_len(env, "a0string", 8, ERL_NIF_LATIN1), + enif_make_string_len(env, a0string, 8, ERL_NIF_LATIN1), + enif_make_string_len(env, a0string0, 9, ERL_NIF_LATIN1)); +} static ErlNifFunc nif_funcs[] = { @@ -656,7 +756,11 @@ static ErlNifFunc nif_funcs[] = {"get_resource", 2, get_resource}, {"release_resource", 1, release_resource}, {"last_resource_dtor_call", 0, last_resource_dtor_call}, - {"make_new_resource", 2, make_new_resource} + {"make_new_resource", 2, make_new_resource}, + {"check_is", 10, check_is}, + {"length_test", 5, length_test}, + {"make_atoms", 0, make_atoms}, + {"make_strings", 0, make_strings} }; |