static inline int match_tuple(ErlNifEnv* env, ERL_NIF_TERM term, State *st){ const ERL_NIF_TERM *tuple; int arity; if(!enif_get_tuple(env, term, &arity, &tuple)) return 0; if(arity > 0){ if(enif_is_atom(env, tuple[0])){ if(arity == 2){ if(enif_is_identical(tuple[0], st->priv->am_struct)){ //struct return match_proplist(env, tuple[1], st); }else if(enif_is_identical(tuple[0], st->priv->am_json)){ //json return match_json(env, tuple[1], st); } } //records if(st->records){ return match_record(env, arity, tuple, st); } } if(arity == 1){ //eep18 return (match_proplist(env, tuple[0], st)); } } return 0; }
static ERL_NIF_TERM stats(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { ERL_NIF_TERM atom; ERL_NIF_TERM ret, q1s, q2s, incrs, wakeups, duds; struct cache *c; if (!enif_is_atom(env, argv[0])) return enif_make_badarg(env); atom = argv[0]; if ((c = get_cache(atom))) { enif_rwlock_rlock(c->cache_lock); q1s = enif_make_uint64(env, c->q1.size); q2s = enif_make_uint64(env, c->q2.size); incrs = enif_make_uint64(env, __sync_fetch_and_add(&(c->incr_count), 0)); wakeups = enif_make_uint64(env, __sync_fetch_and_add(&(c->wakeups), 0)); duds = enif_make_uint64(env, __sync_fetch_and_add(&(c->dud_wakeups), 0)); enif_rwlock_runlock(c->cache_lock); ret = enif_make_tuple7(env, enif_make_uint64(env, c->hit), enif_make_uint64(env, c->miss), q1s, q2s, incrs, wakeups, duds); enif_consume_timeslice(env, 10); return ret; } else { return enif_make_atom(env, "notfound"); } }
static inline int match_atom(ErlNifEnv* env, ERL_NIF_TERM term, State *st){ if(!enif_is_atom(env, term)){ return 0; } if(enif_is_identical(term, st->priv->am_true)){ b_puts(4, "true", st); return 1; }else if(enif_is_identical(term, st->priv->am_false)){ b_puts(5, "false", st); return 1; }else if(enif_is_identical(term, st->priv->am_null)){ b_puts(4, "null", st); return 1; } unsigned len, reserve; b_reserve(256 + 2, st); unsigned char *p = st->cur; if((len = enif_get_atom(env, term, (char*)p + 1, 256U, ERL_NIF_LATIN1))){ *p = '"'; if(!check_str_for_json((unsigned char*)p + 1, len-1, &reserve)){ return 0; } if(reserve > 0){ b_reserve(len + reserve + 2, st); extend_str_to_jstr((unsigned char*)p + 1, len-1, reserve); } st->cur += (len + reserve); b_putc('"', st); return 1; } return 0; }
/* destroy(Cache :: atom()) -- destroys and entire cache destroy(Cache :: atom(), Key :: binary()) -- removes an entry from a cache */ static ERL_NIF_TERM destroy(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { ERL_NIF_TERM atom; struct cache *c; ErlNifBinary kbin; struct cache_node *n; if (!enif_is_atom(env, argv[0])) return enif_make_badarg(env); atom = argv[0]; if ((c = get_cache(atom))) { if (argc == 2) { if (!enif_inspect_binary(env, argv[1], &kbin)) return enif_make_badarg(env); enif_rwlock_rwlock(c->cache_lock); enif_rwlock_rwlock(c->lookup_lock); HASH_FIND(hh, c->lookup, kbin.data, kbin.size, n); if (!n) { enif_rwlock_rwunlock(c->lookup_lock); enif_rwlock_rwunlock(c->cache_lock); return enif_make_atom(env, "notfound"); } enif_mutex_lock(c->ctrl_lock); destroy_cache_node(n); enif_mutex_unlock(c->ctrl_lock); enif_rwlock_rwunlock(c->lookup_lock); enif_rwlock_rwunlock(c->cache_lock); enif_consume_timeslice(env, 50); return enif_make_atom(env, "ok"); } else { enif_mutex_lock(c->ctrl_lock); c->flags |= FL_DYING; enif_mutex_unlock(c->ctrl_lock); enif_cond_broadcast(c->check_cond); enif_thread_join(c->bg_thread, NULL); enif_consume_timeslice(env, 100); return enif_make_atom(env, "ok"); } return enif_make_atom(env, "ok"); } return enif_make_atom(env, "notfound"); }
static void parse_match_capture_options(ErlNifEnv* env, matchoptions& opts, const ERL_NIF_TERM* tuple, int tuplearity) { bool vs_set = false; if (enif_is_atom(env, tuple[1])) { // ValueSpec = all | all_but_first | first | none if (enif_is_atom(env, tuple[1]) > 0) { if (enif_is_identical(tuple[1], a_all)) opts.vs = matchoptions::VS_ALL; else if (enif_is_identical(tuple[1], a_all_but_first)) opts.vs = matchoptions::VS_ALL_BUT_FIRST; else if (enif_is_identical(tuple[1], a_first)) opts.vs = matchoptions::VS_FIRST; else if (enif_is_identical(tuple[1], a_none)) opts.vs = matchoptions::VS_NONE; vs_set = true; } } else if (!enif_is_empty_list(env, tuple[1])) { // ValueSpec = ValueList // ValueList = [ ValueID ] // ValueID = int() | string() | atom() opts.vlist = tuple[1]; vs_set = true; opts.vs = matchoptions::VS_VLIST; } // Type = index | binary if (tuplearity == 3 && vs_set) { if (enif_is_identical(tuple[2], a_index)) opts.ct = matchoptions::CT_INDEX; else if (enif_is_identical(tuple[2], a_binary)) opts.ct = matchoptions::CT_BINARY; } }
jsval to_js_key(ErlNifEnv* env, JSContext* cx, ERL_NIF_TERM term) { if(enif_is_atom(env, term)) { return to_js_special(env, cx, term); } else if(enif_is_binary(env, term)) { return to_js_string(env, cx, term); } else { return JSVAL_VOID; } }
static int atom_to_string(ErlNifEnv* env, ERL_NIF_TERM atom_term, char **bin_str) { unsigned atom_len; char *atom_string; *bin_str = NULL; if(!enif_is_atom(env, atom_term) || !enif_get_atom_length(env, atom_term, &atom_len, ERL_NIF_LATIN1)) return 0; if(!(atom_string = (char*)malloc(atom_len+1))) return 0; if(!enif_get_atom(env, atom_term, atom_string, atom_len+1, ERL_NIF_LATIN1)){ free(atom_string); return 0; } *bin_str = atom_string; return 1; }
/* whereis_send(Type, Name, Message) -> ok | {error, Reason} */ static ERL_NIF_TERM whereis_send(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { whereis_term_data_t to; int type, rc; if (argc != 3 || !enif_is_atom(env, argv[1])) return enif_make_badarg(env); if ((type = whereis_type(argv[0])) == WHEREIS_ERROR_TYPE) return enif_make_badarg(env); rc = whereis_lookup_internal(env, type, argv[1], & to); if (rc == WHEREIS_SUCCESS) rc = whereis_send_internal(env, type, & to, argv[2]); return whereis_result_term(env, rc); }
/* * 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(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; }
/* create(Cache :: atom(), MaxSize :: integer(), MinQ1Size :: integer()) */ static ERL_NIF_TERM create(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { ERL_NIF_TERM atom; ErlNifUInt64 max_size, min_q1_size; struct cache *c; if (!enif_is_atom(env, argv[0])) return enif_make_badarg(env); atom = argv[0]; if (!enif_get_uint64(env, argv[1], &max_size)) return enif_make_badarg(env); if (!enif_get_uint64(env, argv[2], &min_q1_size)) return enif_make_badarg(env); if ((c = get_cache(atom))) { ERL_NIF_TERM ret = enif_make_atom(env, "already_exists"); enif_consume_timeslice(env, 5); enif_rwlock_rwlock(c->cache_lock); /* expansion is safe because we don't have to engage the background thread and won't cause sudden eviction pressure TODO: a nice way to shrink the cache without seizing it up */ if (c->max_size < max_size && c->min_q1_size < min_q1_size) { c->max_size = max_size; c->min_q1_size = min_q1_size; enif_rwlock_rwunlock(c->cache_lock); ret = enif_make_atom(env, "ok"); enif_consume_timeslice(env, 10); } else { enif_rwlock_rwunlock(c->cache_lock); } return ret; } else { c = new_cache(atom, max_size, min_q1_size); enif_consume_timeslice(env, 20); return enif_make_atom(env, "ok"); } }
int enc_key(Encoder* enc, ERL_NIF_TERM key) { char buf[512]; ErlNifBinary bin; if(enif_is_atom(enc->env, key)) { if(!enif_get_atom_compat(enc->env, key, buf, 512)) { enc->error = enif_make_atom(enc->env, "failed_getting_atom_key"); return ERROR; } if(yajl_gen_string(enc->handle, (unsigned char*) buf, strlen(buf)) != yajl_gen_status_ok) { enc->error = enif_make_atom(enc->env, "failed_writing_atom_key"); return ERROR; } return OK; } else if(enif_inspect_iolist_as_binary(enc->env, key, &bin)) { if(yajl_gen_string(enc->handle, bin.data, bin.size) != yajl_gen_status_ok) { enc->error = enif_make_atom(enc->env, "failed_writing_binary_key"); return ERROR; } return OK; } enc->error = enif_make_tuple(enc->env, 2, enif_make_atom(enc->env, "badkey"), key ); return ERROR; }
static mrb_value erl2mruby(ErlNifEnv* env, mrb_state* mrb, ERL_NIF_TERM term) { if (enif_is_atom(env, term)) { unsigned len; enif_get_atom_length(env, term, &len, ERL_NIF_LATIN1); char * atom_str = (char *)malloc(sizeof(char)*(len+1)); int r = enif_get_atom(env, term, atom_str, len+1, ERL_NIF_LATIN1); mrb_value value; if(strncmp(atom_str, "nil", r) == 0){ value = mrb_nil_value(); }else if(strncmp(atom_str, "true", r) == 0){ value = mrb_true_value(); }else if(strncmp(atom_str, "false", r) == 0){ value = mrb_false_value(); }else{ value = mrb_symbol_value(mrb_intern_cstr(mrb, atom_str)); } free(atom_str); return value; } else if (enif_is_binary(env, term)) { ErlNifBinary bin; enif_inspect_binary(env, term, &bin); return mrb_str_new(mrb, (const char *)bin.data, bin.size); } else if (enif_is_number(env, term)) { double d; if (enif_get_double(env, term, &d)) { return mrb_float_value(mrb, (mrb_float)d); } else { ErlNifSInt64 i; enif_get_int64(env, term, &i); return mrb_fixnum_value((mrb_int)i); } } else if (enif_is_empty_list(env, term)) { return mrb_ary_new(mrb); } else if (enif_is_list(env, term)) { unsigned len; enif_get_list_length(env, term, &len); mrb_value ary = mrb_ary_new(mrb); ERL_NIF_TERM cur; for (cur = term; !enif_is_empty_list(env, cur); ) { ERL_NIF_TERM head, tail; enif_get_list_cell(env, cur, &head, &tail); mrb_ary_push(mrb, ary, erl2mruby(env, mrb, head)); cur = tail; } return ary; } else if (enif_is_tuple(env, term)) { int arity; const ERL_NIF_TERM * array; enif_get_tuple(env, term, &arity, &array); unsigned len = 0; enif_get_list_length(env, array[0], &len); mrb_value hash = mrb_hash_new(mrb); ERL_NIF_TERM cur; for(cur = array[0]; !enif_is_empty_list(env, cur); ){ ERL_NIF_TERM head, tail; enif_get_list_cell(env, cur, &head, &tail); const ERL_NIF_TERM * array0; int arity0; enif_get_tuple(env, head, &arity0, &array0); mrb_hash_set(mrb, hash, erl2mruby(env, mrb, array0[0]), erl2mruby(env, mrb, array0[1])); cur = tail; } return hash; } else { return mrb_nil_value(); } }
int enc_json(Encoder* enc, ERL_NIF_TERM term) { int ival; unsigned int uival; long lval; unsigned long ulval; double dval; ERL_NIF_TERM head; ERL_NIF_TERM tail; int arity; const ERL_NIF_TERM* tuple; if(enif_is_atom(enc->env, term)) { return enc_atom(enc, term); } if(enif_is_binary(enc->env, term)) { return enc_binary(enc, term); } if(enif_get_int(enc->env, term, &ival)) { if(yajl_gen_integer(enc->handle, ival) != yajl_gen_status_ok) { enc->error = enif_make_atom(enc->env, "bad_integer"); return ERROR; } return OK; } if(enif_get_uint(enc->env, term, &uival)) { if(yajl_gen_integer(enc->handle, uival) != yajl_gen_status_ok) { enc->error = enif_make_atom(enc->env, "bad_unsigned_integer"); return ERROR; } return OK; } if(enif_get_long(enc->env, term, &lval)) { if(yajl_gen_integer(enc->handle, lval) != yajl_gen_status_ok) { enc->error = enif_make_atom(enc->env, "bad_long"); return ERROR; } return OK; } if(enif_get_ulong(enc->env, term, &ulval)) { if(yajl_gen_integer(enc->handle, ulval) != yajl_gen_status_ok) { enc->error = enif_make_atom(enc->env, "bad_unsigned_long"); return ERROR; } return OK; } if(enif_get_double(enc->env, term, &dval)) { if(yajl_gen_double(enc->handle, dval) != yajl_gen_status_ok) { enc->error = enif_make_atom(enc->env, "bad_double"); return ERROR; } return OK; } if(enif_is_empty_list(enc->env, term)) { if(yajl_gen_array_open(enc->handle) != yajl_gen_status_ok) { enc->error = enif_make_atom(enc->env, "failed_to_open_empty_list"); return ERROR; } if(yajl_gen_array_close(enc->handle) != yajl_gen_status_ok) { enc->error = enif_make_atom(enc->env, "failed_to_close_empty_list"); return ERROR; } return OK; } if(enif_get_list_cell(enc->env, term, &head, &tail)) { return enc_array(enc, head, tail); } if(enif_get_tuple(enc->env, term, &arity, &tuple)) { if(arity == 1) { if(enif_is_empty_list(enc->env, tuple[0])) { if(yajl_gen_map_open(enc->handle) != yajl_gen_status_ok) { enc->error = enif_make_atom(enc->env, "failed_to_open_empty_map"); return ERROR; } if(yajl_gen_map_close(enc->handle) != yajl_gen_status_ok) { enc->error = enif_make_atom(enc->env, "failed_to_close_empty_map"); return ERROR; } return OK; } else if(enif_get_list_cell(enc->env, tuple[0], &head, &tail)) { return enc_map(enc, head, tail); } } } enc->error = enif_make_tuple(enc->env, 2, enif_make_atom(enc->env, "badarg"), term ); return ERROR; }
ERL_NIF_TERM nif_test_from_file(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { if (argc != 1) { #ifndef TRENDS_DEBUG return enif_make_atom(env, "error"); #else return enif_make_atom(env, "error_invalid_argc"); #endif } ErlNifBinary file_path; char trends_file_path[MAX_NAME_LEN]; bool success = enif_inspect_binary(env, argv[0], &file_path); if (success && (file_path.size < MAX_NAME_LEN)) { memcpy(trends_file_path, file_path.data, file_path.size); trends_file_path[file_path.size] = '\0'; #ifdef ERLANG_R14B02 enif_release_binary(&file_path); #else enif_release_binary(env, &file_path); #endif } else { #ifdef ERLANG_R14B02 enif_release_binary(&file_path); #else enif_release_binary(env, &file_path); #endif #ifndef TRENDS_DEBUG return enif_make_atom(env, "error"); #else return enif_make_atom(env, "error_trends_file_path_inspect_bin"); #endif } unsigned char trends_buffer[MAX_LIST_BUFFER_LEN]; unsigned int trends_len = 0; unsigned int trends_count = 0; if (GetTestTrendsFromFile(trends_file_path, trends_buffer, MAX_LIST_BUFFER_LEN, &trends_len, &trends_count) < 0) { #ifndef TRENDS_DEBUG return enif_make_atom(env, "error"); #else return enif_make_atom(env, "error_get_test_trends_failed"); #endif } if (trends_len <= 0 || trends_len >= MAX_LIST_BUFFER_LEN) { #ifndef TRENDS_DEBUG return enif_make_atom(env, "error"); #else return enif_make_atom(env, "error_invalid_trends_len"); #endif } ErlNifBinary trends_bin; int ret_val = 0; #ifdef ERLANG_R14B02 ret_val = enif_alloc_binary(trends_len, &trends_bin); #else ret_val = enif_alloc_binary(env, trends_len, &trends_bin); #endif if (ret_val < 0) { #ifndef TRENDS_DEBUG return enif_make_atom(env, "error"); #else return enif_make_atom(env, "error_tweet_len"); #endif } unsigned int i=0; for (i=0; i<trends_len; i++) { trends_bin.data[i] = *(trends_buffer + i); } ERL_NIF_TERM arg_array[1]; arg_array[0] = enif_make_binary(env, &trends_bin); ERL_NIF_TERM trends_list = nif_get_trends(env, 1, arg_array); if (enif_is_atom(env, trends_list)) { #ifndef TRENDS_DEBUG return enif_make_atom(env, "error"); #else return enif_make_atom(env, "error_get_trends_failed"); #endif } return trends_list; }
static ERL_NIF_TERM nif_notify(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { ErlNifBinary summary; ErlNifBinary body; ErlNifBinary icon; ErlNifBinary category; int urgency = NOTIFY_URGENCY_NORMAL; int timeout = 0; gchar *s_summary = NULL; gchar *s_body = NULL; gchar *s_icon = NULL; gchar *s_category = NULL; ERL_NIF_TERM hints; ERL_NIF_TERM head; ERL_NIF_TERM tail; const ERL_NIF_TERM *array; int arity = 0; NotifyNotification *notify = NULL; ERL_NIF_TERM rv = atom_ok; if (!enif_inspect_iolist_as_binary(env, argv[0], &summary)) return enif_make_badarg(env); if (!enif_inspect_iolist_as_binary(env, argv[1], &body)) return enif_make_badarg(env); if (!enif_inspect_iolist_as_binary(env, argv[2], &icon)) return enif_make_badarg(env); if (!enif_inspect_iolist_as_binary(env, argv[3], &category)) return enif_make_badarg(env); if (!enif_get_int(env, argv[4], &urgency)) return enif_make_badarg(env); if (!enif_get_int(env, argv[5], &timeout)) return enif_make_badarg(env); if (!enif_is_list(env, argv[6])) return enif_make_badarg(env); hints = argv[6]; s_summary = stralloc(&summary); s_body = stralloc(&body); s_icon = stralloc(&icon); s_category = stralloc(&category); if ( (s_summary == NULL) || (s_body == NULL) || (s_icon == NULL) || (s_category == NULL)) { rv = enif_make_tuple2(env, atom_error, atom_nomem); goto ERR; } notify = notify_notification_new(s_summary, s_body, s_icon); notify_notification_set_category(notify, s_category); notify_notification_set_urgency(notify, urgency); notify_notification_set_timeout(notify, timeout); while (enif_get_list_cell(env, hints, &head, &tail)) { ERL_NIF_TERM key; ERL_NIF_TERM value = atom_undefined; if (enif_get_tuple(env, head, &arity, &array)) { switch (arity) { case 2: value = array[1]; key = array[0]; break; default: rv = enif_make_badarg(env); goto ERR; } } else if (enif_is_atom(env, head)) { arity = 0; key = head; } else { rv = enif_make_badarg(env); goto ERR; } if (notify_hints_type(env, notify, arity, key, value) < 0) { rv = enif_make_badarg(env); goto ERR; } hints = tail; } notify_notification_show(notify, NULL); ERR: if (notify) g_object_unref(G_OBJECT(notify)); strfree(s_summary); strfree(s_body); strfree(s_icon); strfree(s_category); return rv; }
ERL_NIF_TERM make_decoder_resource_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]){ unsigned records_cnt, ukeys_cnt, keys_cnt; enif_get_uint(env, argv[0], &records_cnt); enif_get_uint(env, argv[1], &ukeys_cnt); enif_get_uint(env, argv[2], &keys_cnt); PrivData* priv = (PrivData*)enif_priv_data(env); unsigned resource_sz = dec_resource_size(records_cnt, ukeys_cnt, keys_cnt); DecEntry *dec_entry = (DecEntry*)enif_alloc_resource(priv->decoder_RSTYPE, resource_sz); dec_entry->records_cnt = records_cnt; dec_entry->ukeys_cnt = ukeys_cnt; dec_entry->keys_cnt = keys_cnt; ERL_NIF_TERM list, head, tail; int i; ERL_NIF_TERM* ukeys = ukeys_base(dec_entry); list = argv[3]; //UKeys for(i = 0; i < ukeys_cnt; i++){ if(!enif_get_list_cell(env, list, &head, &tail)) goto error; ukeys[i] = head; list = tail; } unsigned* keys = keys_base(dec_entry, ukeys_cnt); list = argv[4]; //KeyNums for(i = 0; i < keys_cnt; i++){ if(!enif_get_list_cell(env, list, &head, &tail)) goto error; if(!enif_get_uint(env, head, &keys[i])) goto error; list = tail; } DecRecord* records = records_base(dec_entry, ukeys_cnt, keys_cnt); long *bit_mask = bit_mask_base(dec_entry, ukeys_cnt, keys_cnt, records_cnt); size_t bit_mask_len = BITS_TO_WORDS(dec_entry->ukeys_cnt); memset((void *)bit_mask, 0, bit_mask_array_size(ukeys_cnt, records_cnt)); const ERL_NIF_TERM *tuple; int arity, k; list = argv[5]; //Records for(i = 0; i < records_cnt; i++){ if(!enif_get_list_cell(env, list, &head, &tail)) goto error; if(!(enif_get_tuple(env, head, &arity, &tuple) && (arity == 3))) goto error; if(!enif_is_atom(env, tuple[0])) goto error; records[i].tag = tuple[0]; if(!enif_get_uint(env, tuple[1], &records[i].keys_off)) goto error; if(!enif_get_uint(env, tuple[2], &records[i].arity)) goto error; list = tail; for(k = 0; k < records[i].arity; k++){ int p = records[i].keys_off + k; //position in keys set_bit(keys[p], bit_mask + (i * bit_mask_len)); } } ERL_NIF_TERM ret = enif_make_resource(env, (void *)dec_entry); enif_release_resource(dec_entry); return ret; error: enif_release_resource(dec_entry); return enif_make_badarg(env); }
static void push_nif_term(lua_State* lua, ERL_NIF_TERM message, ErlNifEnv* env, ErlNifResourceType* resource_type) { const int top = lua_gettop(lua); if(enif_is_atom(env, message)) { push_nif_atom(lua, message, env); } else if(enif_is_binary(env, message)) { // TODO @@@ binary also seems to be the custom types // that erlang makes. This may be OK, but maybe we should // think about putting a special type for them in lua push_nif_binary(lua, message, env); } else if(enif_is_list(env, message)) { if(enif_is_empty_list(env, message)) { luaL_checkstack(lua, 1, ERROR_STACK_MESSAGE); lua_newtable(lua); } else { // TODO @@@ try to send it as an IO list first and // if that fails send it as a regular list push_nif_list(lua, message, env, resource_type); } } else if(enif_is_tuple(env, message)) { push_nif_tuple(lua, message, env, resource_type); } else if(enif_is_pid(env, message)) { push_nif_pid(lua, message, env); } else if(enif_is_ref(env, message)) { push_nif_ref(lua, message, env); } else if(enif_is_exception(env, message)) { //printf("#exception\n"); luaL_checkstack(lua, 1, ERROR_STACK_MESSAGE); lua_pushliteral(lua, "sending an exception is not supported"); } else if(enif_is_fun(env, message)) { //printf("#fun\n"); luaL_checkstack(lua, 1, ERROR_STACK_MESSAGE); lua_pushliteral(lua, "sending a function reference is not supported"); } else if(enif_is_port(env, message)) { //printf("#port\n"); luaL_checkstack(lua, 1, ERROR_STACK_MESSAGE); lua_pushliteral(lua, "sending a port is not supported"); } else { // thank you r14 -- must be a number push_nif_number(lua, message, env); } assert(lua_gettop(lua) == top+1); }
static ERL_NIF_TERM re2_match_ret_vlist(ErlNifEnv* env, const autohandle<re2::RE2>& re, const re2::StringPiece& s, const matchoptions& opts, std::vector<re2::StringPiece>& group, int n) { std::vector<ERL_NIF_TERM> vec; const std::map<std::string, int>& nmap = re->NamedCapturingGroups(); ERL_NIF_TERM VL,VH,VT; // empty StringPiece for unfound ValueIds const re2::StringPiece empty; for (VL=opts.vlist; enif_get_list_cell(env, VL, &VH, &VT); VL=VT) { int nid = 0; if (enif_get_int(env, VH, &nid) && nid > 0) { // ValueID int() if (nid < n) { const re2::StringPiece match = group[nid]; ERL_NIF_TERM res; if (!match.empty()) res = mres(env, s, group[nid], opts.ct); else res = mres(env, s, empty, opts.ct); if (enif_is_identical(res, a_err_alloc_binary)) return error(env, a_err_alloc_binary); else vec.push_back(res); } else { vec.push_back(mres(env, s, empty, opts.ct)); } } else if (enif_is_atom(env, VH)) { // ValueID atom() unsigned atom_len; char *a_id = alloc_atom(env, VH, &atom_len); if (a_id == NULL) return error(env, a_err_enif_alloc); if (enif_get_atom(env, VH, a_id, atom_len, ERL_NIF_LATIN1) > 0) { std::map<std::string, int>::const_iterator it = nmap.find(a_id); ERL_NIF_TERM res; if (it != nmap.end()) res = mres(env, s, group[it->second], opts.ct); else res = mres(env, s, empty, opts.ct); if (enif_is_identical(res, a_err_alloc_binary)) return error(env, a_err_alloc_binary); else vec.push_back(res); } else { enif_free(a_id); return error(env, a_err_get_atom); } enif_free(a_id); } else { // ValueID string() unsigned str_len; char *str_id = alloc_str(env, VH, &str_len); if (str_id == NULL) return error(env, a_err_enif_alloc); if (enif_get_string(env, VH, str_id, str_len, ERL_NIF_LATIN1) > 0) { std::map<std::string, int>::const_iterator it = nmap.find(str_id); ERL_NIF_TERM res; if (it != nmap.end()) res = mres(env, s, group[it->second], opts.ct); else res = mres(env, s, empty, opts.ct); if (enif_is_identical(res, a_err_alloc_binary)) return error(env, a_err_alloc_binary); else vec.push_back(res); } else { enif_free(str_id); return error(env, a_err_get_string); } enif_free(str_id); } } ERL_NIF_TERM list = enif_make_list_from_array(env,&vec[0],vec.size()); return enif_make_tuple2(env, a_match, list); }
jsval to_js(ErlNifEnv* env, JSContext* cx, ERL_NIF_TERM term) { int intval; unsigned int uintval; long longval; unsigned long ulongval; double doubleval; ERL_NIF_TERM head; ERL_NIF_TERM tail; const ERL_NIF_TERM* tuple; int arity; if(enif_is_atom(env, term)) { return to_js_special(env, cx, term); } if(enif_is_binary(env, term)) { return to_js_string(env, cx, term); } if(enif_is_empty_list(env, term)) { return to_js_empty_array(cx); } if(enif_get_int(env, term, &intval)) { return to_js_number(cx, (double) intval); } if(enif_get_uint(env, term, &uintval)) { return to_js_number(cx, (double) uintval); } if(enif_get_long(env, term, &longval)) { return to_js_number(cx, (double) longval); } if(enif_get_ulong(env, term, &ulongval)) { return to_js_number(cx, (double) ulongval); } if(enif_get_double(env, term, &doubleval)) { return to_js_number(cx, doubleval); } // enif doesn't seem to have any API to decode bignums, so use lower-level functions: if(is_big(term) && big_to_double(term, &doubleval) == 0) { return to_js_number(cx, doubleval); } if(enif_get_list_cell(env, term, &head, &tail)) { return to_js_array(env, cx, head, tail); } if(enif_get_tuple(env, term, &arity, &tuple)) { if(arity == 1) { return to_js_object(env, cx, tuple[0]); } } return JSVAL_VOID; }
ERL_NIF_TERM nif_test_from_file(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { char tweets_buffer[MAX_LIST_BUFFER_LEN]; memset(tweets_buffer, 0, MAX_LIST_BUFFER_LEN); int out_length = 0; if (argc != 1) { #ifndef SENTIMENT_DEBUG return enif_make_atom(env, "error"); #else return enif_make_atom(env, "error_invalid_argc"); #endif } else { char file_name_str[MAX_NAME_LEN]; memset(file_name_str, 0, MAX_NAME_LEN); ErlNifBinary file_name; if (enif_inspect_binary(env, argv[0], &file_name)) { memcpy(file_name_str, file_name.data, file_name.size); file_name_str[file_name.size] = '\0'; #ifdef ERLANG_R14B02 enif_release_binary(&file_name); #else enif_release_binary(env, &file_name); #endif } else { #ifdef ERLANG_R14B02 enif_release_binary(&file_name); #else enif_release_binary(env, &file_name); #endif #ifndef SENTIMENT_DEBUG return enif_make_atom(env, "error"); #else return enif_make_atom(env, "error_file_name"); #endif } if (GetTestTweetsFromFile(file_name_str, MAX_LIST_BUFFER_LEN, tweets_buffer, &out_length) < 0) { #ifndef SENTIMENT_DEBUG return enif_make_atom(env, "error"); #else return enif_make_atom(env, "error_get_test_tweets_for_user"); #endif } } if (0 == out_length || out_length > MAX_LIST_BUFFER_LEN) { #ifndef SENTIMENT_DEBUG return enif_make_atom(env, "error"); #else return enif_make_atom(env, "error_out_length"); #endif } ErlNifBinary tweet; char *tweet_start = tweets_buffer; char *tweet_end = strstr(tweet_start, "|"); int ret_val = 0; unsigned int i = 0; unsigned int tweet_len = 0; ERL_NIF_TERM arg_array[1]; ERL_NIF_TERM tuple6; ERL_NIF_TERM tuple6_list = enif_make_list(env, 0); unsigned int error_count = 0; while (tweet_start && tweet_end && *tweet_end != '\0') { tweet_end = strstr(tweet_start, "|"); if (!tweet_end) break; *tweet_end = '\0'; tweet_len = tweet_end - tweet_start; if (tweet_len <= 0 || tweet_len >= MAX_BUFFER_LEN) { #ifndef SENTIMENT_DEBUG return enif_make_atom(env, "error"); #else return enif_make_atom(env, "error_out_length"); #endif } #ifdef ERLANG_R14B02 ret_val = enif_alloc_binary(tweet_len, &tweet); #else ret_val = enif_alloc_binary(env, tweet_len, &tweet); #endif if (ret_val < 0) { #ifndef SENTIMENT_DEBUG return enif_make_atom(env, "error"); #else return enif_make_atom(env, "error_tweet_len"); #endif } for (i=0; i<tweet_len; i++) { tweet.data[i] = *(tweet_start + i); } arg_array[0] = enif_make_binary(env, &tweet); tuple6 = nif_get_sentiment(env, 1, arg_array); if (enif_is_atom(env, tuple6)) { error_count++; } else { tuple6_list = enif_make_list_cell(env, tuple6, tuple6_list); } *tweet_end = '|'; tweet_start = tweet_end + 1; } tweet_start = NULL; tweet_end = NULL; return tuple6_list; }
static ERL_NIF_TERM put(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { ERL_NIF_TERM atom; ErlNifBinary kbin, vbin; struct cache *c; struct cache_node *n, *ng; ErlNifUInt64 lifetime = 0; if (!enif_is_atom(env, argv[0])) return enif_make_badarg(env); atom = argv[0]; if (!enif_inspect_binary(env, argv[1], &kbin)) return enif_make_badarg(env); if (!enif_inspect_binary(env, argv[2], &vbin)) return enif_make_badarg(env); if ((c = get_cache(atom))) { enif_consume_timeslice(env, 1); } else { /* if we've been asked to put() in to a cache that doesn't exist yet then we should create it! */ ErlNifUInt64 max_size, min_q1_size; if (!enif_get_uint64(env, argv[3], &max_size)) return enif_make_badarg(env); if (!enif_get_uint64(env, argv[4], &min_q1_size)) return enif_make_badarg(env); c = new_cache(atom, max_size, min_q1_size); enif_consume_timeslice(env, 20); } if (argc > 5) if (!enif_get_uint64(env, argv[5], &lifetime)) return enif_make_badarg(env); n = enif_alloc(sizeof(*n)); memset(n, 0, sizeof(*n)); n->c = c; n->vsize = vbin.size; n->ksize = kbin.size; n->size = vbin.size + kbin.size; n->key = enif_alloc(kbin.size); memcpy(n->key, kbin.data, kbin.size); n->val = enif_alloc_resource(value_type, vbin.size); memcpy(n->val, vbin.data, vbin.size); n->q = &(c->q1); if (lifetime) { clock_now(&(n->expiry)); n->expiry.tv_sec += lifetime; } enif_rwlock_rwlock(c->cache_lock); enif_rwlock_rwlock(c->lookup_lock); HASH_FIND(hh, c->lookup, kbin.data, kbin.size, ng); if (ng) { enif_mutex_lock(c->ctrl_lock); destroy_cache_node(ng); enif_mutex_unlock(c->ctrl_lock); } TAILQ_INSERT_HEAD(&(c->q1.head), n, entry); c->q1.size += n->size; HASH_ADD_KEYPTR(hh, c->lookup, n->key, n->ksize, n); if (lifetime) { struct cache_node *rn; rn = RB_INSERT(expiry_tree, &(c->expiry_head), n); /* it's possible to get two timestamps that are the same, if this happens just bump us forwards by 1 usec until we're unique */ while (rn != NULL) { ++(n->expiry.tv_nsec); rn = RB_INSERT(expiry_tree, &(c->expiry_head), n); } } enif_rwlock_rwunlock(c->lookup_lock); enif_rwlock_rwunlock(c->cache_lock); enif_cond_broadcast(c->check_cond); enif_consume_timeslice(env, 50); return enif_make_atom(env, "ok"); }
ERL_NIF_TERM encode_iter(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { Encoder* e; jiffy_st* st = (jiffy_st*) enif_priv_data(env); ERL_NIF_TERM ret = 0; ERL_NIF_TERM stack; ERL_NIF_TERM curr; ERL_NIF_TERM item; const ERL_NIF_TERM* tuple; int arity; ErlNifSInt64 lval; double dval; size_t start; size_t processed; if(argc != 3) { return enif_make_badarg(env); } else if(!enif_get_resource(env, argv[0], st->res_enc, (void**) &e)) { return enif_make_badarg(env); } else if(!enif_is_list(env, argv[1])) { return enif_make_badarg(env); } else if(!enif_is_list(env, argv[2])) { return enif_make_badarg(env); } if(!enc_init(e, env)) { return enif_make_badarg(env); } stack = argv[1]; e->iolist = argv[2]; start = e->iosize + e->i; while(!enif_is_empty_list(env, stack)) { processed = (e->iosize + e->i) - start; if(should_yield(processed, e->bytes_per_iter)) { consume_timeslice(env, processed, e->bytes_per_iter); return enif_make_tuple4( env, st->atom_iter, argv[0], stack, e->iolist ); } if(!enif_get_list_cell(env, stack, &curr, &stack)) { ret = enc_error(e, "internal_error"); goto done; } if(enif_is_identical(curr, e->atoms->ref_object)) { if(!enif_get_list_cell(env, stack, &curr, &stack)) { ret = enc_error(e, "internal_error"); goto done; } if(enif_is_empty_list(env, curr)) { if(!enc_end_object(e)) { ret = enc_error(e, "internal_error"); goto done; } continue; } if(!enif_get_list_cell(env, curr, &item, &curr)) { ret = enc_error(e, "internal_error"); goto done; } if(!enif_get_tuple(env, item, &arity, &tuple)) { ret = enc_obj_error(e, "invalid_object_member", item); goto done; } if(arity != 2) { ret = enc_obj_error(e, "invalid_object_member_arity", item); goto done; } if(!enc_comma(e)) { ret = enc_error(e, "internal_error"); goto done; } if(!enc_string(e, tuple[0])) { ret = enc_obj_error(e, "invalid_object_member_key", tuple[0]); goto done; } if(!enc_colon(e)) { ret = enc_error(e, "internal_error"); goto done; } stack = enif_make_list_cell(env, curr, stack); stack = enif_make_list_cell(env, e->atoms->ref_object, stack); stack = enif_make_list_cell(env, tuple[1], stack); } else if(enif_is_identical(curr, e->atoms->ref_array)) { if(!enif_get_list_cell(env, stack, &curr, &stack)) { ret = enc_error(e, "internal_error"); goto done; } if(enif_is_empty_list(env, curr)) { if(!enc_end_array(e)) { ret = enc_error(e, "internal_error"); goto done; } continue; } if(!enc_comma(e)) { ret = enc_error(e, "internal_error"); goto done; } if(!enif_get_list_cell(env, curr, &item, &curr)) { ret = enc_error(e, "internal_error"); goto done; } stack = enif_make_list_cell(env, curr, stack); stack = enif_make_list_cell(env, e->atoms->ref_array, stack); stack = enif_make_list_cell(env, item, stack); } else if(enif_compare(curr, e->atoms->atom_null) == 0) { if(!enc_literal(e, "null", 4)) { ret = enc_error(e, "null"); goto done; } } else if(e->use_nil && enif_compare(curr, e->atoms->atom_nil) == 0) { if(!enc_literal(e, "null", 4)) { ret = enc_error(e, "null"); goto done; } } else if(enif_compare(curr, e->atoms->atom_true) == 0) { if(!enc_literal(e, "true", 4)) { ret = enc_error(e, "true"); goto done; } } else if(enif_compare(curr, e->atoms->atom_false) == 0) { if(!enc_literal(e, "false", 5)) { ret = enc_error(e, "false"); goto done; } } else if(enif_is_binary(env, curr)) { if(!enc_string(e, curr)) { ret = enc_obj_error(e, "invalid_string", curr); goto done; } } else if(enif_is_atom(env, curr)) { if(!enc_string(e, curr)) { ret = enc_obj_error(e, "invalid_string", curr); goto done; } } else if(enif_get_int64(env, curr, &lval)) { if(!enc_long(e, lval)) { ret = enc_error(e, "internal_error"); goto done; } } else if(enif_get_double(env, curr, &dval)) { if(!enc_double(e, dval)) { ret = enc_error(e, "internal_error"); goto done; } } else if(enif_get_tuple(env, curr, &arity, &tuple)) { ret = enc_obj_error(e, "invalid_ejson", curr); goto done; #if MAP_TYPE_PRESENT } else if(enif_is_map(env, curr)) { if(!enc_map_to_ejson(env, curr, &curr)) { ret = enc_error(e, "internal_error"); goto done; } stack = enif_make_list_cell(env, curr, stack); #endif } else if(enif_is_list(env, curr)) { if(enif_is_empty_list(env, curr)) { if(!enc_start_array(e) || !enc_end_array(e)) { ret = enc_error(e, "internal_error"); goto done; } continue; } if(!enif_get_list_cell(env, curr, &item, &curr)) { ret = enc_error(e, "internal_error"); goto done; } if(!enif_get_tuple(env, item, &arity, &tuple)) { if(!enc_start_array(e)) { ret = enc_error(e, "internal_error"); goto done; } stack = enif_make_list_cell(env, curr, stack); stack = enif_make_list_cell(env, e->atoms->ref_array, stack); stack = enif_make_list_cell(env, item, stack); } else { if(!enc_start_object(e)) { ret = enc_error(e, "internal_error"); goto done; } if(arity == 0) { if(!enc_end_object(e)) { ret = enc_error(e, "internal_error"); goto done; } continue; } else if(arity != 2) { ret = enc_obj_error(e, "invalid_object_member_arity", item); goto done; } if(!enc_string(e, tuple[0])) { ret = enc_obj_error(e, "invalid_object_member_key", tuple[0]); goto done; } if(!enc_colon(e)) { ret = enc_error(e, "internal_error"); goto done; } stack = enif_make_list_cell(env, curr, stack); stack = enif_make_list_cell(env, e->atoms->ref_object, stack); stack = enif_make_list_cell(env, tuple[1], stack); } } else { if(!enc_unknown(e, curr)) { ret = enc_error(e, "internal_error"); goto done; } } } if(!enc_done(e, &item)) { ret = enc_error(e, "internal_error"); goto done; } if(e->iolen == 0) { ret = item; } else { ret = enif_make_tuple2(env, e->atoms->atom_partial, item); } done: processed = (e->iosize + e->i) - start; consume_timeslice(env, processed, e->bytes_per_iter); return ret; }
static inline int enc_string(Encoder* e, ERL_NIF_TERM val) { ErlNifBinary bin; char atom[512]; unsigned char* data; size_t size; int esc_extra = 0; int ulen; int uval; int i; if(enif_is_binary(e->env, val)) { if(!enif_inspect_binary(e->env, val, &bin)) { return 0; } data = bin.data; size = bin.size; } else if(enif_is_atom(e->env, val)) { if(!enif_get_atom(e->env, val, atom, 512, ERL_NIF_LATIN1)) { return 0; } data = (unsigned char*) atom; size = strlen(atom); } else { return 0; } i = 0; while(i < size) { switch((char) data[i]) { case '\"': case '\\': case '\b': case '\f': case '\n': case '\r': case '\t': esc_extra += 1; i++; continue; default: if(data[i] < 0x20) { esc_extra += 5; i++; continue; } else if(data[i] < 0x80) { i++; continue; } ulen = utf8_validate(&(data[i]), size - i); if(ulen < 0) { return 0; } if(e->uescape) { uval = utf8_to_unicode(&(data[i]), ulen); if(uval < 0) { return 0; } esc_extra += utf8_esc_len(uval); if(ulen < 0) { return 0; } } i += ulen; } } if(!enc_ensure(e, size + esc_extra + 2)) { return 0; } e->p[e->i++] = '\"'; i = 0; while(i < size) { switch((char) data[i]) { case '\"': case '\\': e->p[e->i++] = '\\'; e->u[e->i++] = data[i]; i++; continue; case '\b': e->p[e->i++] = '\\'; e->p[e->i++] = 'b'; i++; continue; case '\f': e->p[e->i++] = '\\'; e->p[e->i++] = 'f'; i++; continue; case '\n': e->p[e->i++] = '\\'; e->p[e->i++] = 'n'; i++; continue; case '\r': e->p[e->i++] = '\\'; e->p[e->i++] = 'r'; i++; continue; case '\t': e->p[e->i++] = '\\'; e->p[e->i++] = 't'; i++; continue; default: if(data[i] < 0x20) { ulen = unicode_uescape(data[i], &(e->p[e->i])); if(ulen < 0) { return 0; } e->i += ulen; i++; } else if((data[i] & 0x80) && e->uescape) { uval = utf8_to_unicode(&(data[i]), size-i); if(uval < 0) { return 0; } ulen = unicode_uescape(uval, &(e->p[e->i])); if(ulen < 0) { return 0; } e->i += ulen; ulen = utf8_len(uval); if(ulen < 0) { return 0; } i += ulen; } else { e->u[e->i++] = data[i++]; } } } e->p[e->i++] = '\"'; e->count++; return 1; }
ERL_NIF_TERM nif_test_twitter_timeline(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { char tweets_buffer[MAX_LIST_BUFFER_LEN]; memset(tweets_buffer, 0, MAX_LIST_BUFFER_LEN); int out_length = 0; if (argc == 1) { char user_name_str[MAX_NAME_LEN]; memset(user_name_str, 0, MAX_NAME_LEN); ErlNifBinary user_name; if (enif_inspect_binary(env, argv[0], &user_name)) { memcpy(user_name_str, user_name.data, user_name.size); user_name_str[user_name.size] = '\0'; #ifdef ERLANG_R14B02 enif_release_binary(&user_name); #else enif_release_binary(env, &user_name); #endif } else { #ifdef ERLANG_R14B02 enif_release_binary(&user_name); #else enif_release_binary(env, &user_name); #endif #ifndef LD_DEBUG return enif_make_atom(env, "error"); #else return enif_make_atom(env, "error_user_name"); #endif } if (GetTestTweets(user_name_str, MAX_LIST_BUFFER_LEN, tweets_buffer, &out_length) < 0) { #ifndef LD_DEBUG return enif_make_atom(env, "error"); #else return enif_make_atom(env, "error_get_test_tweets_for_user"); #endif } } else { if (GetTestTweets(NULL, MAX_LIST_BUFFER_LEN, tweets_buffer, &out_length) < 0) { #ifndef LD_DEBUG return enif_make_atom(env, "error"); #else return enif_make_atom(env, "error_get_test_tweets_for_null_user"); #endif } } if (0 == out_length || out_length > MAX_LIST_BUFFER_LEN) { #ifndef LD_DEBUG return enif_make_atom(env, "error"); #else return enif_make_atom(env, "error_out_length"); #endif } ErlNifBinary tweet; char *tweet_start = tweets_buffer; char *tweet_end = strstr(tweet_start, "|"); int ret_val = 0; unsigned int i = 0; unsigned int tweet_len = 0; ERL_NIF_TERM arg_array[1]; ERL_NIF_TERM tuple2_list = enif_make_list(env, 0); while (tweet_start && tweet_end && *tweet_end != '\0') { tweet_end = strstr(tweet_start, "|"); if (!tweet_end) break; *tweet_end = '\0'; tweet_len = tweet_end - tweet_start; if (tweet_len <= 0 || tweet_len >= MAX_BUFFER_LEN) { #ifndef LD_DEBUG return enif_make_atom(env, "error"); #else return enif_make_atom(env, "error_tweet_length"); #endif } #ifdef ERLANG_R14B02 ret_val = enif_alloc_binary(tweet_len, &tweet); #else ret_val = enif_alloc_binary(env, tweet_len, &tweet); #endif if (ret_val < 0) { #ifndef LD_DEBUG return enif_make_atom(env, "error"); #else return enif_make_atom(env, "error_alloc_bin_failed_for_tweet"); #endif } for (i=0; i<tweet_len; i++) { tweet.data[i] = *(tweet_start + i); } arg_array[0] = enif_make_binary(env, &tweet); ERL_NIF_TERM tuple2 = nif_detect_lang(env, 1, arg_array); if (enif_is_atom(env, tuple2)) { #ifndef LD_DEBUG return enif_make_atom(env, "error"); #else return enif_make_atom(env, "error_not_a_tuple2"); #endif //} else if (enif_is_tuple(env, tuple2)) { } else { tuple2_list = enif_make_list_cell(env, tuple2, tuple2_list); /* #ifndef LD_DEBUG return enif_make_atom(env, "error"); #else return enif_make_atom(env, "error_undefined_detect_lang_output"); #endif */ } *tweet_end = '|'; tweet_start = tweet_end + 1; } tweet_start = NULL; tweet_end = NULL; return tuple2_list; }
static ERL_NIF_TERM get(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { ERL_NIF_TERM atom; ErlNifBinary kbin; struct cache *c; struct cache_node *n; struct cache_incr_node *in; struct timespec now; int incrqs, hashv, bkt; ERL_NIF_TERM ret; ErlNifTid tid; if (!enif_is_atom(env, argv[0])) return enif_make_badarg(env); atom = argv[0]; if (!enif_inspect_binary(env, argv[1], &kbin)) return enif_make_badarg(env); if ((c = get_cache(atom))) { enif_rwlock_rlock(c->lookup_lock); HASH_FIND(hh, c->lookup, kbin.data, kbin.size, n); if (!n) { enif_rwlock_runlock(c->lookup_lock); __sync_add_and_fetch(&c->miss, 1); enif_consume_timeslice(env, 10); return enif_make_atom(env, "notfound"); } if (n->expiry.tv_sec != 0) { clock_now(&now); if (n->expiry.tv_sec < now.tv_sec) { enif_rwlock_runlock(c->lookup_lock); __sync_add_and_fetch(&c->miss, 1); enif_consume_timeslice(env, 10); return enif_make_atom(env, "notfound"); } } in = enif_alloc(sizeof(*in)); memset(in, 0, sizeof(*in)); in->node = n; __sync_add_and_fetch(&c->hit, 1); tid = enif_thread_self(); HASH_SFH(&tid, sizeof(ErlNifTid), N_INCR_BKT, hashv, bkt); enif_mutex_lock(c->incr_lock[bkt]); TAILQ_INSERT_TAIL(&(c->incr_head[bkt]), in, entry); enif_mutex_unlock(c->incr_lock[bkt]); incrqs = __sync_add_and_fetch(&(c->incr_count), 1); ret = enif_make_resource_binary(env, n->val, n->val, n->vsize); enif_rwlock_runlock(c->lookup_lock); if (incrqs > 1024) enif_cond_broadcast(c->check_cond); enif_consume_timeslice(env, 20); return ret; } return enif_make_atom(env, "notfound"); }
static void ks_selector_arg(ks_returner_t *ret, ks_pattern_t *pattern, ERL_NIF_TERM arg) { unsigned size; char *string; int result; ErlNifSInt64 integer; if (ret->ready != B_TRUE) { if (enif_is_atom(ret->env, arg)) { enif_get_atom_length(ret->env, arg, &size, ERL_NIF_LATIN1); string = (char *)(malloc(sizeof (char) * (size + 1))); if (string == NULL) { ret->term = EKSTAT_ERROR("atom malloc"); ret->ready = B_TRUE; return; } result = enif_get_atom(ret->env, arg, string, size + 1, ERL_NIF_LATIN1); if (result == 0) { ret->term = enif_make_badarg(ret->env); ret->ready = B_TRUE; } else { if (strncmp(string, "_", result) == 0) { pattern->pstr = "*"; pattern->free = B_FALSE; } else { ret->term = enif_make_badarg(ret->env); ret->ready = B_TRUE; } free(string); } } else if (enif_is_list(ret->env, arg)) { enif_get_list_length(ret->env, arg, &size); string = (char *)(malloc(sizeof (char) * (size + 1))); if (string == NULL) { ret->term = EKSTAT_ERROR("list malloc"); ret->ready = B_TRUE; return; } result = enif_get_string(ret->env, arg, string, size + 1, ERL_NIF_LATIN1); if (result == 0) { ret->term = enif_make_badarg(ret->env); ret->ready = B_TRUE; } else { pattern->pstr = (char *)(ks_safe_strdup(ret, string)); pattern->free = B_TRUE; } free(string); } else if (enif_is_number(ret->env, arg)) { if (enif_get_int64(ret->env, arg, &integer)) { (void) asprintf(&string, "%d", integer); pattern->pstr = (char *)(ks_safe_strdup(ret, string)); pattern->free = B_TRUE; } else { ret->term = enif_make_badarg(ret->env); ret->ready = B_TRUE; } free(string); } else { ret->term = enif_make_badarg(ret->env); ret->ready = B_TRUE; } } }
ERL_NIF_TERM encode(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { Encoder enc; Encoder* e = &enc; ErlNifBinary bin; ERL_NIF_TERM ret; ERL_NIF_TERM stack; ERL_NIF_TERM curr; ERL_NIF_TERM item; const ERL_NIF_TERM* tuple; int arity; ErlNifSInt64 lval; double dval; if(argc != 2) { return enif_make_badarg(env); } if(!enc_init(e, env, argv[1], &bin)) { return enif_make_badarg(env); } stack = enif_make_list(env, 1, argv[0]); while(!enif_is_empty_list(env, stack)) { if(!enif_get_list_cell(env, stack, &curr, &stack)) { ret = enc_error(e, "internal_error"); goto done; } if(enif_is_identical(curr, e->atoms->ref_object)) { if(!enif_get_list_cell(env, stack, &curr, &stack)) { ret = enc_error(e, "internal_error"); goto done; } if(enif_is_empty_list(env, curr)) { if(!enc_end_object(e)) { ret = enc_error(e, "internal_error"); goto done; } continue; } if(!enif_get_list_cell(env, curr, &item, &curr)) { ret = enc_error(e, "internal_error"); goto done; } if(!enif_get_tuple(env, item, &arity, &tuple)) { ret = enc_error(e, "invalid_object_pair"); goto done; } if(arity != 2) { ret = enc_error(e, "invalid_object_pair"); goto done; } if(!enc_comma(e)) { ret = enc_error(e, "internal_error"); goto done; } if(!enc_string(e, tuple[0])) { ret = enc_error(e, "invalid_object_key"); goto done; } if(!enc_colon(e)) { ret = enc_error(e, "internal_error"); goto done; } stack = enif_make_list_cell(env, curr, stack); stack = enif_make_list_cell(env, e->atoms->ref_object, stack); stack = enif_make_list_cell(env, tuple[1], stack); } else if(enif_is_identical(curr, e->atoms->ref_array)) { if(!enif_get_list_cell(env, stack, &curr, &stack)) { ret = enc_error(e, "internal_error"); goto done; } if(enif_is_empty_list(env, curr)) { if(!enc_end_array(e)) { ret = enc_error(e, "internal_error"); goto done; } continue; } if(!enc_comma(e)) { ret = enc_error(e, "internal_error"); goto done; } if(!enif_get_list_cell(env, curr, &item, &curr)) { ret = enc_error(e, "internal_error"); goto done; } stack = enif_make_list_cell(env, curr, stack); stack = enif_make_list_cell(env, e->atoms->ref_array, stack); stack = enif_make_list_cell(env, item, stack); } else if(enif_compare(curr, e->atoms->atom_null) == 0) { if(!enc_literal(e, "null", 4)) { ret = enc_error(e, "null"); goto done; } } else if(enif_compare(curr, e->atoms->atom_true) == 0) { if(!enc_literal(e, "true", 4)) { ret = enc_error(e, "true"); goto done; } } else if(enif_compare(curr, e->atoms->atom_false) == 0) { if(!enc_literal(e, "false", 5)) { ret = enc_error(e, "false"); goto done; } } else if(enif_is_binary(env, curr)) { if(!enc_string(e, curr)) { ret = enc_error(e, "invalid_string"); goto done; } } else if(enif_is_atom(env, curr)) { if(!enc_string(e, curr)) { ret = enc_error(e, "invalid_string"); goto done; } } else if(enif_get_int64(env, curr, &lval)) { if(!enc_long(e, lval)) { ret = enc_error(e, "internal_error"); goto done; } } else if(enif_get_double(env, curr, &dval)) { if(!enc_double(e, dval)) { ret = enc_error(e, "internal_error"); goto done; } } else if(enif_get_tuple(env, curr, &arity, &tuple)) { if(arity != 1) { ret = enc_error(e, "invalid_ejson"); goto done; } if(!enif_is_list(env, tuple[0])) { ret = enc_error(e, "invalid_object"); goto done; } if(!enc_start_object(e)) { ret = enc_error(e, "internal_error"); goto done; } if(enif_is_empty_list(env, tuple[0])) { if(!enc_end_object(e)) { ret = enc_error(e, "internal_error"); goto done; } continue; } if(!enif_get_list_cell(env, tuple[0], &item, &curr)) { ret = enc_error(e, "internal_error"); goto done; } if(!enif_get_tuple(env, item, &arity, &tuple)) { ret = enc_error(e, "invalid_object_member"); goto done; } if(arity != 2) { ret = enc_error(e, "invalid_object_member_arity"); goto done; } if(!enc_string(e, tuple[0])) { ret = enc_error(e, "invalid_object_member_key"); goto done; } if(!enc_colon(e)) { ret = enc_error(e, "internal_error"); goto done; } stack = enif_make_list_cell(env, curr, stack); stack = enif_make_list_cell(env, e->atoms->ref_object, stack); stack = enif_make_list_cell(env, tuple[1], stack); } else if(enif_is_list(env, curr)) { if(!enc_start_array(e)) { ret = enc_error(e, "internal_error"); goto done; } if(enif_is_empty_list(env, curr)) { if(!enc_end_array(e)) { ret = enc_error(e, "internal_error"); goto done; } continue; } if(!enif_get_list_cell(env, curr, &item, &curr)) { ret = enc_error(e, "internal_error"); goto done; } stack = enif_make_list_cell(env, curr, stack); stack = enif_make_list_cell(env, e->atoms->ref_array, stack); stack = enif_make_list_cell(env, item, stack); } else { if(!enc_unknown(e, curr)) { ret = enc_error(e, "internal_error"); goto done; } } } if(!enc_done(e, &item)) { ret = enc_error(e, "internal_error"); goto done; } if(e->iolen == 0) { ret = item; } else { ret = enif_make_tuple2(env, e->atoms->atom_partial, item); } done: enc_destroy(e); return ret; }
ERL_NIF_TERM nif_test_twitter_timeline(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { char tweets_buffer[MAX_LIST_BUFFER_LEN]; memset(tweets_buffer, 0, MAX_LIST_BUFFER_LEN); int out_length = 0; if (argc == 1) { char user_name_str[MAX_NAME_LEN]; memset(user_name_str, 0, MAX_NAME_LEN); ErlNifBinary user_name; if (enif_inspect_binary(env, argv[0], &user_name)) { memcpy(user_name_str, user_name.data, user_name.size); user_name_str[user_name.size] = '\0'; #ifdef ERLANG_R14B02 enif_release_binary(&user_name); #else enif_release_binary(env, &user_name); #endif } else { #ifdef ERLANG_R14B02 enif_release_binary(&user_name); #else enif_release_binary(env, &user_name); #endif #ifndef TRENDS_DEBUG return enif_make_atom(env, "error"); #else return enif_make_atom(env, "error_user_name"); #endif } if (GetTestTweets(user_name_str, MAX_LIST_BUFFER_LEN, tweets_buffer, &out_length) < 0) { #ifndef TRENDS_DEBUG return enif_make_atom(env, "error"); #else return enif_make_atom(env, "error_get_test_tweets_for_user"); #endif } } else { if (GetTestTweets(NULL, MAX_LIST_BUFFER_LEN, tweets_buffer, &out_length) < 0) { #ifndef TRENDS_DEBUG return enif_make_atom(env, "error"); #else return enif_make_atom(env, "error_get_test_tweets_for_null_user"); #endif } } if (0 == out_length || out_length > MAX_LIST_BUFFER_LEN) { #ifndef TRENDS_DEBUG return enif_make_atom(env, "error"); #else return enif_make_atom(env, "error_out_length"); #endif } ErlNifBinary tweets_bin; unsigned int tweets_len = out_length; int ret_val = 0; unsigned int i = 0; ERL_NIF_TERM arg_array[1]; ERL_NIF_TERM trends_list = enif_make_list(env, 0); #ifdef ERLANG_R14B02 ret_val = enif_alloc_binary(tweets_len, &tweets_bin); #else ret_val = enif_alloc_binary(env, tweets_len, &tweets_bin); #endif if (ret_val < 0) { #ifndef TRENDS_DEBUG return enif_make_atom(env, "error"); #else return enif_make_atom(env, "error_tweet_len"); #endif } for (i=0; i<tweets_len; i++) { tweets_bin.data[i] = *(tweets_buffer + i); } arg_array[0] = enif_make_binary(env, &tweets_bin); trends_list = nif_get_trends(env, 1, arg_array); if (enif_is_atom(env, trends_list)) { return enif_make_atom(env, "error_nif_get_trends"); } return trends_list; }
ERL_NIF_TERM make_encoder_resource_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]){ unsigned rs_len, fs_len, bin_sz; enif_get_uint(env, argv[0], &rs_len); enif_get_uint(env, argv[1], &fs_len); enif_get_uint(env, argv[4], &bin_sz); PrivData* priv = (PrivData*)enif_priv_data(env); unsigned resource_sz = enc_resource_size(rs_len, fs_len); EncEntry *enc_entry = (EncEntry*)enif_alloc_resource(priv->encoder_RSTYPE, resource_sz); //memset(enc_entry, 0, resource_sz); enc_entry->records_cnt = rs_len; enc_entry->fields_cnt = fs_len; if(!enif_alloc_binary(bin_sz + 1, &enc_entry->bin)) goto error; //memset(enc_entry->bin.data, 0, bin_sz + 1); ErlNifBinary ebin; enif_inspect_binary(env, argv[5], &ebin); memcpy(enc_entry->bin.data, ebin.data , ebin.size); ERL_NIF_TERM list, head, tail; list = argv[2]; int i = 0; while(enif_get_list_cell(env, list, &head, &tail)){ const ERL_NIF_TERM *tuple; int arity; unsigned ip; enif_get_tuple(env, head, &arity, &tuple); EncRecord *records = enc_records_base(enc_entry); records[i].tag = tuple[0]; enif_get_uint(env, tuple[1], &ip); records[i].fds_offset = ip; enif_get_uint(env, tuple[2], &ip); records[i].arity = ip; i++; list = tail; } list = argv[3]; i = 0; while(enif_get_list_cell(env, list, &head, &tail)){ const ERL_NIF_TERM *tuple; int arity; unsigned ip; enif_get_tuple(env, head, &arity, &tuple); EncField *fields = enc_fields_base(enc_entry); enif_get_uint(env, tuple[0], &ip); fields[i].offset = ip; enif_get_uint(env, tuple[1], &ip); fields[i].size = ip; i++; list = tail; } list = argv[6]; if(!enif_get_list_length(env, list, &(enc_entry->ignored_len))) goto error; enc_entry->ignored = (ERL_NIF_TERM*)enif_alloc(enc_entry->ignored_len*sizeof(ERL_NIF_TERM)); i = 0; while(enif_get_list_cell(env, list, &head, &tail)){ // ignored term should be atoms if(enif_is_atom(env, head)){ enc_entry->ignored[i] = head; }else{ enif_free(enc_entry->ignored); goto error; } i++; list = tail; } ERL_NIF_TERM ret = enif_make_resource(env, (void *)enc_entry); enif_release_resource(enc_entry); return ret; error: enif_release_resource(enc_entry); return enif_make_badarg(env); }
int less_ejson(int depth, couch_ejson_ctx_t* ctx, ERL_NIF_TERM a, ERL_NIF_TERM b) { int aIsAtom, bIsAtom; int aIsBin, bIsBin; int aIsNumber, bIsNumber; int aIsList, bIsList; int aArity, bArity; const ERL_NIF_TERM *aProps, *bProps; /* * Avoid too much recursion. Normally there isn't more than a few levels * of recursion, as in practice view keys do not go beyond 1 to 3 levels * of nesting. In case of too much recursion, signal it to the Erlang land * via an exception and do the EJSON comparison in Erlang land. */ if (depth > MAX_DEPTH) { ctx->error = 1; return 0; } aIsAtom = enif_is_atom(ctx->env, a); bIsAtom = enif_is_atom(ctx->env, b); if (aIsAtom) { if (bIsAtom) { int aSortOrd, bSortOrd; if ((aSortOrd = atom_sort_order(ctx->env, a)) == -1) { ctx->error = 1; return 0; } if ((bSortOrd = atom_sort_order(ctx->env, b)) == -1) { ctx->error = 1; return 0; } return aSortOrd - bSortOrd; } return -1; } if (bIsAtom) { return 1; } aIsNumber = term_is_number(ctx->env, a); bIsNumber = term_is_number(ctx->env, b); if (aIsNumber) { if (bIsNumber) { return enif_compare_compat(ctx->env, a, b); } return -1; } if (bIsNumber) { return 1; } aIsBin = enif_is_binary(ctx->env, a); bIsBin = enif_is_binary(ctx->env, b); if (aIsBin) { if (bIsBin) { ErlNifBinary binA, binB; enif_inspect_binary(ctx->env, a, &binA); enif_inspect_binary(ctx->env, b, &binB); return compare_strings(ctx, binA, binB); } return -1; } if (bIsBin) { return 1; } aIsList = enif_is_list(ctx->env, a); bIsList = enif_is_list(ctx->env, b); if (aIsList) { if (bIsList) { return compare_lists(depth, ctx, a, b); } return -1; } if (bIsList) { return 1; } if (!enif_get_tuple(ctx->env, a, &aArity, &aProps)) { ctx->error = 1; return 0; } if ((aArity != 1) || !enif_is_list(ctx->env, aProps[0])) { ctx->error = 1; return 0; } if (!enif_get_tuple(ctx->env, b, &bArity, &bProps)) { ctx->error = 1; return 0; } if ((bArity != 1) || !enif_is_list(ctx->env, bProps[0])) { ctx->error = 1; return 0; } return compare_props(depth, ctx, aProps[0], bProps[0]); }