static ERL_NIF_TERM setup_2(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { unsigned int channel; unsigned long speed; int error; if (argc != 2 || !enif_is_number(env, argv[0]) || !enif_is_number(env, argv[1])) { return enif_make_badarg(env); } if (!enif_get_uint(env, argv[0], &channel)) { return enif_make_badarg(env); } if (!enif_get_ulong(env, argv[1], &speed)) { return enif_make_badarg(env); } if (speed < 500000 || speed > 32000000) { return enif_make_badarg(env); } switch (channel) { case 0: if (state0.fd != 0) { return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_string(env, "channel already opened", ERL_NIF_LATIN1)); } else { state0.env = env; state0.fd = wiringPiSPISetup(channel, speed); if (state0.fd == 0) { error = errno; return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_int(env, error)); } else { return enif_make_tuple2(env, enif_make_atom(env, "ok"), enif_make_int(env, channel)); } } break; case 1: if (state1.fd != 0) { return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_string(env, "channel already opened", ERL_NIF_LATIN1)); } else { state1.env = env; state1.fd = wiringPiSPISetup(channel, speed); if (state1.fd == 0) { error = errno; return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_int(env, error)); } else { return enif_make_tuple2(env, enif_make_atom(env, "ok"), enif_make_int(env, channel)); } } break; default: return enif_make_badarg(env); } }
static ERL_NIF_TERM pwrite_nif_impl(efile_data_t *d, ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { ErlNifIOVec vec, *input = &vec; Sint64 bytes_written, offset; ERL_NIF_TERM tail; if(argc != 2 || !enif_is_number(env, argv[0]) || !enif_inspect_iovec(env, 64, argv[1], &tail, &input)) { return enif_make_badarg(env); } if(!enif_get_int64(env, argv[0], &offset) || offset < 0) { return posix_error_to_tuple(env, EINVAL); } bytes_written = efile_pwritev(d, offset, input->iov, input->iovcnt); if(bytes_written < 0) { return posix_error_to_tuple(env, d->posix_errno); } if(!enif_is_empty_list(env, tail)) { ASSERT(bytes_written > 0); return enif_make_tuple3(env, am_continue, enif_make_int64(env, bytes_written), tail); } return am_ok; }
static ERL_NIF_TERM close_1(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { unsigned int channel; if (argc != 1 || !enif_is_number(env, argv[0])) { return enif_make_badarg(env); } if (!enif_get_uint(env, argv[0], &channel)) { return enif_make_badarg(env); } switch (channel) { case 0: if (state0.fd != 0) { close(state0.fd); state0.fd = 0; } break; case 1: if (state1.fd != 0) { close(state1.fd); state1.fd = 0; } break; default: return enif_make_badarg(env); } return enif_make_atom(env, "ok"); }
static ERL_NIF_TERM allocate_nif_impl(efile_data_t *d, ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { Sint64 offset, length; if(argc != 2 || !enif_is_number(env, argv[0]) || !enif_is_number(env, argv[1])) { return enif_make_badarg(env); } if(!enif_get_int64(env, argv[0], &offset) || !enif_get_int64(env, argv[1], &length) || (offset < 0 || length < 0)) { return posix_error_to_tuple(env, EINVAL); } if(!efile_allocate(d, offset, length)) { return posix_error_to_tuple(env, d->posix_errno); } return am_ok; }
static ERL_NIF_TERM tempo_strftime(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { ERL_NIF_TERM res; ERL_NIF_TERM buf; double clock_raw; double usecs; time_t clock; ErlNifBinary format; char fmt_str[MAX_SIZE] = {0}; char buf_str[MAX_SIZE] = {0}; size_t buf_len; int overflow; struct tm tm; if (argc != 2 || !enif_is_binary(env, argv[0]) || !enif_inspect_binary(env, argv[0], &format) || !format.size /* disallow empty format. */ #if ERL_NIF_MAJOR_VERSION >= 2 && ERL_NIF_MINOR_VERSION >= 3 || !enif_is_number(env, argv[1]) #endif || !enif_get_double(env, argv[1], &clock_raw) || !enif_get_binary_str(&format, fmt_str)) { res = BADARG; } else { usecs = clock_raw - ((ErlNifSInt64) clock_raw); overflow = 0; clock = int64_to_time_t((ErlNifSInt64) clock_raw, &overflow); if (overflow != 0.) { /* HACK(Sergei): even though the exact type of 'time_t' is unspecified, on most systems it seem to be a plain 'int'. */ res = TUPLE_ERROR(ATOM("time_overflow")); } else { memset(&tm, 0, sizeof(struct tm)); if (!gmtime_r(&clock, &tm)) { res = TUPLE_ERROR(ATOM("invalid_time")); } else { expand_custom_formatters(fmt_str, usecs); buf_len = strftime(buf_str, MAX_SIZE, fmt_str, &tm); memcpy(enif_make_new_binary(env, buf_len, &buf), &buf_str, buf_len); res = TUPLE_OK(buf); } } } return res; }
static ERL_NIF_TERM pread_nif_impl(efile_data_t *d, ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { Sint64 bytes_read, block_size, offset; SysIOVec read_vec[1]; ErlNifBinary result; ASSERT(argc == 2); if(!enif_is_number(env, argv[0]) || !enif_is_number(env, argv[1])) { return enif_make_badarg(env); } if(!enif_get_int64(env, argv[0], &offset) || !enif_get_int64(env, argv[1], &block_size) || (offset < 0 || block_size < 0)) { return posix_error_to_tuple(env, EINVAL); } if(!enif_alloc_binary(block_size, &result)) { return posix_error_to_tuple(env, ENOMEM); } read_vec[0].iov_base = result.data; read_vec[0].iov_len = result.size; bytes_read = efile_preadv(d, offset, read_vec, 1); if(bytes_read < 0) { enif_release_binary(&result); return posix_error_to_tuple(env, d->posix_errno); } else if(bytes_read == 0) { enif_release_binary(&result); return am_eof; } if(bytes_read < block_size && !enif_realloc_binary(&result, bytes_read)) { ERTS_INTERNAL_ERROR("Failed to shrink pread result."); } return enif_make_tuple2(env, am_ok, enif_make_binary(env, &result)); }
static ERL_NIF_TERM advise_nif_impl(efile_data_t *d, ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { enum efile_advise_t advise; Sint64 offset, length; if(argc != 3 || !enif_is_number(env, argv[0]) || !enif_is_number(env, argv[1])) { return enif_make_badarg(env); } if(!enif_get_int64(env, argv[0], &offset) || !enif_get_int64(env, argv[1], &length) || (offset < 0 || length < 0)) { return posix_error_to_tuple(env, EINVAL); } if(enif_is_identical(argv[2], am_normal)) { advise = EFILE_ADVISE_NORMAL; } else if(enif_is_identical(argv[2], am_random)) { advise = EFILE_ADVISE_RANDOM; } else if(enif_is_identical(argv[2], am_sequential)) { advise = EFILE_ADVISE_SEQUENTIAL; } else if(enif_is_identical(argv[2], am_will_need)) { advise = EFILE_ADVISE_WILL_NEED; } else if(enif_is_identical(argv[2], am_dont_need)) { advise = EFILE_ADVISE_DONT_NEED; } else if(enif_is_identical(argv[2], am_no_reuse)) { advise = EFILE_ADVISE_NO_REUSE; } else { /* The tests check for EINVAL instead of badarg. Sigh. */ return posix_error_to_tuple(env, EINVAL); } if(!efile_advise(d, offset, length, advise)) { return posix_error_to_tuple(env, d->posix_errno); } return am_ok; }
/*-----------------------------------------------------------------------------------------------------------------------*/ static ERL_NIF_TERM set_double_field(ErlNifEnv* env, int32_t argc, ERL_NIF_TERM const argv[]) { ERL_NIF_TERM parser_res; ERL_NIF_TERM msg_res; ERL_NIF_TERM group_res; ParserRes* parser = NULL; FIXMsg* msg = NULL; FIXGroup* group = NULL; ERL_NIF_TERM res = get_parser_msg_group(env, argv[0], &parser_res, &msg_res, &group_res, &parser, &msg, &group); if (res != ok_atom) { return res; } int32_t tagNum = 0; if (!enif_get_int(env, argv[1], &tagNum)) { return make_error(env, FIX_FAILED, "Wrong tag num."); } if (!enif_is_number(env, argv[2])) { return make_error(env, FIX_FAILED, "Value is not a double."); } double val = 0.0; if (!enif_get_double(env, argv[2], &val)) { int64_t lval = 0; enif_get_int64(env, argv[2], &lval); val = lval; } ERL_NIF_TERM ret = ok_atom; FIXError* error = NULL; pthread_rwlock_wrlock(&parser->lock); FIXErrCode err = fix_msg_set_double(msg, group, tagNum, val, &error); pthread_rwlock_unlock(&parser->lock); if (err == FIX_FAILED) { ret = make_parser_error(env, fix_error_get_code(error), fix_error_get_text(error)); fix_error_free(error); } return ret; }
static ERL_NIF_TERM xfer_2(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { unsigned int channel, length; int result, i, val; uint8_t *buffer; ERL_NIF_TERM cell, head, tail, list; if (argc < 2 || !enif_is_number(env, argv[0]) || !enif_is_list(env, argv[1])) { return enif_make_badarg(env); } if (!enif_get_uint(env, argv[0], &channel) || channel < 0 || channel > 1) { return enif_make_badarg(env); } if (!enif_get_list_length(env, argv[1], &length) || length == 0) { return enif_make_badarg(env); } buffer = (uint8_t *) enif_alloc(sizeof(uint8_t) * length); list = argv[1]; for (i = 0; enif_get_list_cell(env, list, &head, &tail); ++i, list = tail) { if (!enif_get_int(env, head, &val)) { return enif_make_badarg(env); } buffer[i] = val; } result = wiringPiSPIDataRW(channel, buffer, length); if (result == -1) { result = errno; enif_free(buffer); return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_int(env, result)); } list = enif_make_list(env, 0); for (i = length - 1; i >= 0; --i) { cell = enif_make_uint(env, (unsigned int) buffer[i]); list = enif_make_list_cell(env, cell, list); } enif_free(buffer); return enif_make_tuple2(env, enif_make_atom(env, "ok"), list); }
/* This undocumented function reads a pointer and then reads the data block * described by said pointer. It was reverse-engineered from the old * implementation so while all tests pass it may not be entirely correct. Our * current understanding is as follows: * * Pointer layout: * * <<Size:1/integer-unit:32, Offset:1/integer-unit:32>> * * Where Offset is the -absolute- address to the data block. * * *) If we fail to read the pointer block in its entirety, we return eof. * *) If the provided max_payload_size is larger than Size, we return eof. * *) If we fail to read any data whatsoever at Offset, we return * {ok, {Size, Offset, eof}} * *) Otherwise, we return {ok, {Size, Offset, Data}}. Note that the size * of Data may be smaller than Size if we encounter EOF before we could * read the entire block. * * On errors we'll return {error, posix()} regardless of whether they * happened before or after reading the pointer block. */ static ERL_NIF_TERM ipread_s32bu_p32bu_nif_impl(efile_data_t *d, ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { Sint64 payload_offset, payload_size; SysIOVec read_vec[1]; Sint64 bytes_read; ErlNifBinary payload; if(argc != 2 || !enif_is_number(env, argv[0]) || !enif_is_number(env, argv[1])) { return enif_make_badarg(env); } { Sint64 max_payload_size, pointer_offset; unsigned char pointer_block[8]; if(!enif_get_int64(env, argv[0], &pointer_offset) || !enif_get_int64(env, argv[1], &max_payload_size) || (pointer_offset < 0 || max_payload_size >= 1u << 31)) { return posix_error_to_tuple(env, EINVAL); } read_vec[0].iov_base = pointer_block; read_vec[0].iov_len = sizeof(pointer_block); bytes_read = efile_preadv(d, pointer_offset, read_vec, 1); if(bytes_read < 0) { return posix_error_to_tuple(env, d->posix_errno); } else if(bytes_read < sizeof(pointer_block)) { return am_eof; } payload_size = (Uint32)get_int32(&pointer_block[0]); payload_offset = (Uint32)get_int32(&pointer_block[4]); if(payload_size > max_payload_size) { return am_eof; } } if(!enif_alloc_binary(payload_size, &payload)) { return posix_error_to_tuple(env, ENOMEM); } read_vec[0].iov_base = payload.data; read_vec[0].iov_len = payload.size; bytes_read = efile_preadv(d, payload_offset, read_vec, 1); if(bytes_read < 0) { return posix_error_to_tuple(env, d->posix_errno); } else if(bytes_read == 0) { enif_release_binary(&payload); return enif_make_tuple2(env, am_ok, enif_make_tuple3(env, enif_make_uint(env, payload_size), enif_make_uint(env, payload_offset), am_eof)); } if(bytes_read < payload.size && !enif_realloc_binary(&payload, bytes_read)) { ERTS_INTERNAL_ERROR("Failed to shrink ipread payload."); } return enif_make_tuple2(env, am_ok, enif_make_tuple3(env, enif_make_uint(env, payload_size), enif_make_uint(env, payload_offset), enif_make_binary(env, &payload))); }
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(); } }
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; } } }