Example #1
0
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;  
}
Example #2
0
File: nif.c Project: arekinath/e2qc
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");
	}
}
Example #3
0
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;
}
Example #4
0
File: nif.c Project: arekinath/e2qc
/* 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");
}
Example #5
0
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;
    }
}
Example #6
0
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;
    }
}
Example #7
0
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;
}
Example #8
0
/* 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);
}
Example #9
0
/*
 * 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;
}
Example #10
0
File: nif.c Project: arekinath/e2qc
/* 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");
	}
}
Example #11
0
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;
}
Example #12
0
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();
  }
}
Example #13
0
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; 
}
Example #15
0
    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;
}
Example #16
0
File: jsonx.c Project: ymv/jsonx
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);
}
Example #17
0
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);
}
Example #18
0
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);
}
Example #19
0
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;
}
Example #21
0
File: nif.c Project: arekinath/e2qc
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");
}
Example #22
0
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;
}
Example #23
0
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;
}
Example #25
0
File: nif.c Project: arekinath/e2qc
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");
}
Example #26
0
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;
		}
	}
}
Example #27
0
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;
}
Example #29
0
File: jsonx.c Project: ymv/jsonx
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);
}
Example #30
0
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]);
}