static ERL_NIF_TERM parse(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { XML_Parser **parser; int is_final, res, errcode; ErlNifBinary stream; char *errstring; assert(argc == 3); if (!enif_get_resource(env, argv[0], PARSER_POINTER, (void **)&parser)) return enif_make_badarg(env); if (!enif_is_binary(env, argv[1])) return enif_make_badarg(env); enif_get_int(env, argv[2], &is_final); enif_inspect_binary(env, argv[1], &stream); expat_parser *parser_data = XML_GetUserData((XML_Parser)(*parser)); parser_data->result = enif_make_list(env, 0); parser_data->env = env; XML_SetUserData((XML_Parser)(*parser), parser_data); res = XML_Parse((XML_Parser)(*parser), (const char *)stream.data, stream.size, is_final); if(!res) { errcode = XML_GetErrorCode((XML_Parser)(*parser)); errstring = (char *)XML_ErrorString(errcode); return enif_make_tuple(env, 2, ERROR, enif_make_string(env, errstring, ERL_NIF_LATIN1)); } return enif_make_tuple(env, 2, OK, parser_data->result); };
static void *start_element_handler(expat_parser *parser_data, const XML_Char *name, const XML_Char **atts) { ErlNifBinary element_name; ERL_NIF_TERM attrs_list = enif_make_list(parser_data->env, 0); int i; element_name = encode_name(parser_data, name); for(i = 0; atts[i]; i += 2); while(i) { ErlNifBinary attr_name, attr_value; enif_alloc_binary(strlen(atts[i-1]), &attr_value); strcpy((char *) attr_value.data, (const char *)atts[i-1]); attr_name = encode_name(parser_data, atts[i-2]); ERL_NIF_TERM attr = enif_make_tuple(parser_data->env, 2, enif_make_binary(parser_data->env, &attr_name), enif_make_binary(parser_data->env, &attr_value)); attrs_list = enif_make_list_cell(parser_data->env, attr, attrs_list); i -= 2; }; if(parser_data->xmlns) attrs_list = enif_make_list_cell(parser_data->env, parser_data->xmlns, attrs_list); parser_data->xmlns = (ERL_NIF_TERM)NULL; ERL_NIF_TERM event = enif_make_tuple(parser_data->env, 3, XML_ELEMENT_START, enif_make_binary(parser_data->env, &element_name), attrs_list); parser_data->result = enif_make_list_cell(parser_data->env, event, parser_data->result); return NULL; };
static void *start_element_handler(expat_parser *parser_data, const XML_Char *name, const XML_Char **atts) { ERL_NIF_TERM element_name; ERL_NIF_TERM attrs_list = enif_make_list(parser_data->env, 0); int i; element_name = encode_name(parser_data, name); for(i = 0; atts[i]; i += 2); while(i) { ERL_NIF_TERM attr_name, attr_value; size_t atts_len = strlen(atts[i-1]); unsigned char *attr_data = enif_make_new_binary(parser_data->env, atts_len, &attr_value); strncpy((char*)attr_data, (const char *)atts[i-1], atts_len); attr_name = encode_name(parser_data, atts[i-2]); ERL_NIF_TERM attr = enif_make_tuple(parser_data->env, 2, attr_name, attr_value); attrs_list = enif_make_list_cell(parser_data->env, attr, attrs_list); i -= 2; }; ERL_NIF_TERM event = enif_make_tuple(parser_data->env, 4, XML_ELEMENT_START, element_name, parser_data->xmlns, attrs_list); parser_data->result = enif_make_list_cell(parser_data->env, event, parser_data->result); parser_data->xmlns = enif_make_list(parser_data->env, 0); return NULL; };
ERL_NIF_TERM entry_to_term(ErlNifEnv *env, const git_index_entry *entry) { ErlNifBinary id, path; size_t len; if (geef_oid_bin(&id, &entry->id) < 0) return geef_oom(env); len = strlen(entry->path); if (!enif_alloc_binary(len, &path)) { enif_release_binary(&id); return geef_oom(env); } memcpy(path.data, entry->path, len); return enif_make_tuple(env, 13, atoms.ok, enif_make_int64(env, entry->ctime.seconds), enif_make_int64(env, entry->mtime.seconds), enif_make_uint(env, entry->dev), enif_make_uint(env, entry->ino), enif_make_uint(env, entry->mode), enif_make_uint(env, entry->uid), enif_make_uint(env, entry->gid), enif_make_int64(env, entry->file_size), enif_make_binary(env, &id), enif_make_uint(env, entry->flags), enif_make_uint(env, entry->flags_extended), enif_make_binary(env, &path)); }
static void *namespace_decl_handler(expat_parser *parser_data, const XML_Char *prefix, const XML_Char *uri) { ERL_NIF_TERM ns_prefix_bin, ns_uri_bin, ns_pair; if(uri == NULL) { /* parser_data->xmlns = (ERL_NIF_TERM)NULL; */ fprintf(stderr, "URI IS NULL?\n"); return NULL; } if(prefix) { size_t prefix_len = strlen(prefix); unsigned char *ns_prefix_data = enif_make_new_binary(parser_data->env, prefix_len, &ns_prefix_bin); strncpy((char*)ns_prefix_data, (const char *)prefix, prefix_len); } else { ns_prefix_bin = NONE; } size_t uri_len = strlen(uri); unsigned char *ns_uri_data = enif_make_new_binary(parser_data->env, uri_len, &ns_uri_bin); strncpy((char*)ns_uri_data, uri, uri_len); ns_pair = enif_make_tuple(parser_data->env, 2, ns_uri_bin, ns_prefix_bin); parser_data->xmlns = enif_make_list_cell(parser_data->env, ns_pair, parser_data->xmlns); return NULL; };
static ERL_NIF_TERM error_tuple(ErlNifEnv *env, char *err) { return enif_make_tuple(env, 2, enif_make_atom(env, "error"), enif_make_atom(env, err)); }
static ERL_NIF_TERM read_info_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { posix_errno_t posix_errno; efile_fileinfo_t info = {0}; efile_path_t path; int follow_links; if(argc != 2 || !enif_get_int(env, argv[1], &follow_links)) { return enif_make_badarg(env); } if((posix_errno = efile_marshal_path(env, argv[0], &path))) { return posix_error_to_tuple(env, posix_errno); } else if((posix_errno = efile_read_info(&path, follow_links, &info))) { return posix_error_to_tuple(env, posix_errno); } /* #file_info as declared in file.hrl */ return enif_make_tuple(env, 14, am_file_info, enif_make_uint64(env, info.size), efile_filetype_to_atom(info.type), efile_access_to_atom(info.access), enif_make_int64(env, MAX(EFILE_MIN_FILETIME, info.a_time)), enif_make_int64(env, MAX(EFILE_MIN_FILETIME, info.m_time)), enif_make_int64(env, MAX(EFILE_MIN_FILETIME, info.c_time)), enif_make_uint(env, info.mode), enif_make_uint(env, info.links), enif_make_uint(env, info.major_device), enif_make_uint(env, info.minor_device), enif_make_uint(env, info.inode), enif_make_uint(env, info.uid), enif_make_uint(env, info.gid) ); }
static void *namespace_decl_handler(expat_parser *parser_data, const XML_Char *prefix, const XML_Char *uri) { ErlNifBinary ns_prefix_bin, ns_uri_bin; ERL_NIF_TERM ns_prefix, ns_uri, ns_pair; if(uri == NULL) { /* parser_data->xmlns = (ERL_NIF_TERM)NULL; */ fprintf(stderr, "URI IS NULL?\n"); return NULL; } if(prefix) { enif_alloc_binary(strlen(prefix), &ns_prefix_bin); strcpy((char *)ns_prefix_bin.data, (const char *)prefix); ns_prefix = enif_make_binary(parser_data->env, &ns_prefix_bin); } else { ns_prefix = NONE; } enif_alloc_binary(strlen(uri), &ns_uri_bin); strcpy((char *)ns_uri_bin.data, uri); ns_uri = enif_make_binary(parser_data->env, &ns_uri_bin); ns_pair = enif_make_tuple(parser_data->env, 2, ns_uri, ns_prefix); parser_data->xmlns = enif_make_list_cell(parser_data->env, ns_pair, parser_data->xmlns); return NULL; };
static ERL_NIF_TERM do_column_types(ErlNifEnv *env, sqlite3_stmt *stmt) { int i, size; const char *type; ERL_NIF_TERM *array; ERL_NIF_TERM column_types; size = sqlite3_column_count(stmt); if(size == 0) return enif_make_tuple(env, 0); else if(size < 0) return make_error_tuple(env, "invalid_column_count"); array = (ERL_NIF_TERM *) enif_alloc(sizeof(ERL_NIF_TERM) * size); if(!array) return make_error_tuple(env, "no_memory"); for(i = 0; i < size; i++) { type = sqlite3_column_decltype(stmt, i); if(type == NULL) { type = "nil"; } array[i] = make_atom(env, type); } column_types = enif_make_tuple_from_array(env, array, size); enif_free(array); return column_types; }
static ERL_NIF_TERM no_mem_error(ErlNifEnv* env) { return enif_make_tuple(env, 2, enif_make_atom(env, "error"), enif_make_atom(env, "insufficient_memory")); }
static ERL_NIF_TERM error_tuple(ErlNifEnv *env, char *err) { return enif_make_tuple(env, 2, atom_error, enif_make_string(env, err, ERL_NIF_LATIN1)); }
static void *namespace_decl_handler(expat_parser *parser_data, const XML_Char *prefix, const XML_Char *uri) { ErlNifBinary ns_name, ns_value; if(uri == NULL) { parser_data->xmlns = (ERL_NIF_TERM)NULL; return NULL; } if(prefix) { enif_alloc_binary(strlen(prefix)+6, &ns_name); strcpy((char *)ns_name.data, "xmlns:"); strcpy((char *)ns_name.data+6, (const char *)prefix); } else { enif_alloc_binary(5, &ns_name); strcpy((char *)ns_name.data, "xmlns"); } enif_alloc_binary(strlen(uri), &ns_value); strcpy((char *)ns_value.data, uri); parser_data->xmlns = enif_make_tuple(parser_data->env, 2, enif_make_binary(parser_data->env, &ns_name), enif_make_binary(parser_data->env, &ns_value)); return NULL; };
static ERL_NIF_TERM new_parser(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { XML_Parser parser; expat_parser *parser_data = (expat_parser *)enif_alloc(sizeof(expat_parser)); ERL_NIF_TERM parser_resource; // this is the variant from esl/exml:208d5e17e547b303b310627e3e525b57b2843e83 /*parser = XML_ParserCreate_MM("UTF-8", &ms, "\n");*/ // this makes the tests pass, but according to expat documentation it turns namespace support off /*parser = XML_ParserCreate_MM("UTF-8", &ms, NULL);*/ // this is a try to preserve namespace support but make the tests pass; // this is the character defined as a macro in xmlwf sources for namespace-enabled parser /*XML_Char namespaceSeparator = '\001';*/ /*parser = XML_ParserCreate_MM("UTF-8", &ms, &namespaceSeparator);*/ parser = XML_ParserCreate_MM("UTF-8", &ms, ":"); parser_data->env = env; parser_data->xmlns = (ERL_NIF_TERM)NULL; init_parser(parser, parser_data); XML_Parser *xml_parser = (XML_Parser *)enif_alloc_resource(PARSER_POINTER, sizeof(XML_Parser)); *xml_parser = parser; parser_resource = enif_make_resource(env, (void *)xml_parser); enif_release_resource(xml_parser); return enif_make_tuple(env, 2, OK, parser_resource); };
ERL_NIF_TERM make_empty_document(ErlNifEnv *env, int return_maps) { if(return_maps) { return enif_make_new_map(env); } return enif_make_tuple(env, 0); }
static void *end_element_handler(expat_parser *parser_data, const XML_Char *name) { ERL_NIF_TERM element_name = encode_name(parser_data, name); ERL_NIF_TERM event = enif_make_tuple(parser_data->env, 2, XML_ELEMENT_END, element_name); parser_data->result = enif_make_list_cell(parser_data->env, event, parser_data->result); return NULL; };
int enc_map(Encoder* enc, ERL_NIF_TERM head, ERL_NIF_TERM tail) { int arity; const ERL_NIF_TERM* tuple; if(yajl_gen_map_open(enc->handle) != yajl_gen_status_ok) { enc->error = enif_make_atom(enc->env, "failed_to_open_map"); return ERROR; } do { if(!enif_get_tuple(enc->env, head, &arity, &tuple)) { enc->error = enif_make_tuple(enc->env, 2, enif_make_atom(enc->env, "badarg"), head ); return ERROR; } if(arity != 2) { enc->error = enif_make_tuple(enc->env, 2, enif_make_atom(enc->env, "badarity"), head ); return ERROR; } if(enc_key(enc, tuple[0]) != OK) return ERROR; if(enc_json(enc, tuple[1]) != OK) return ERROR; } while(enif_get_list_cell(enc->env, tail, &head, &tail)); if(yajl_gen_map_close(enc->handle) != yajl_gen_status_ok) { enc->error = enif_make_atom(enc->env, "failed_to_close_map"); return ERROR; } return OK; }
static void *character_data_handler(expat_parser *parser_data, const XML_Char *s, int len) { ERL_NIF_TERM cdata; unsigned char *cdata_data = enif_make_new_binary(parser_data->env, len, &cdata); strncpy((char*)cdata_data, (const char *)s, len); ERL_NIF_TERM event = enif_make_tuple(parser_data->env, 2, XML_CDATA, cdata); parser_data->result = enif_make_list_cell(parser_data->env, event, parser_data->result); return NULL; };
static ERL_NIF_TERM atom_to_bin(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { ErlNifBinary obin; unsigned size; int n; if (!enif_get_int(env,argv[1],(int*)&size) || !enif_alloc_binary(size,&obin)) { return enif_make_badarg(env); } n = enif_get_atom(env, argv[0], (char*)obin.data, size, ERL_NIF_LATIN1); return enif_make_tuple(env, 2, enif_make_int(env,n), enif_make_binary(env,&obin)); }
static void *character_data_handler(expat_parser *parser_data, const XML_Char *s, int len) { ErlNifBinary cdata; enif_alloc_binary(len, &cdata); strncpy((char *)cdata.data, (const char *)s, len); ERL_NIF_TERM event = enif_make_tuple(parser_data->env, 2, XML_CDATA, enif_make_binary(parser_data->env, &cdata)); parser_data->result = enif_make_list_cell(parser_data->env, event, parser_data->result); return NULL; };
static int decode_map_key(void* ctx, const unsigned char* data, unsigned int size) { ErlNifBinary bin; if(!enif_alloc_binary_compat(ENV(ctx), size, &bin)) { return CANCEL; } memcpy(bin.data, data, size); add_to_head(ctx, enif_make_tuple(ENV(ctx), 2, enif_make_int(ENV(ctx), 3), enif_make_binary(ENV(ctx), &bin))); return CONTINUE; }
static int decode_number(void * ctx, const char * numberVal, unsigned int numberLen) { // scan in the input to see if it's a float or int int numberType = 0; // 0 means integer, 1 means float unsigned int i; ErlNifBinary bin; int missingDot = 1; unsigned int expPos; for(i=0; i<numberLen; i++) { switch (numberVal[i]) { case '.': missingDot = 0; numberType = 1; // it's a float goto loopend; case 'E': case 'e': expPos = i; numberType = 1; // it's a float goto loopend; } } loopend: if ((numberType == 1) && missingDot) { if(!enif_alloc_binary_compat(ENV(ctx), numberLen + 2, &bin)) { return CANCEL; } memcpy(bin.data, numberVal, expPos); bin.data[expPos] = '.'; bin.data[expPos + 1] = '0'; memcpy(bin.data + expPos + 2, numberVal + expPos, numberLen - expPos); } else { if(!enif_alloc_binary_compat(ENV(ctx), numberLen, &bin)) { return CANCEL; } memcpy(bin.data, numberVal, numberLen); } add_to_head(ctx, enif_make_tuple(ENV(ctx), 2, enif_make_int(ENV(ctx), numberType), enif_make_binary(ENV(ctx), &bin))); return CONTINUE; }
static ERL_NIF_TERM make_error(yajl_handle handle, ErlNifEnv* env) { char* yajlError = (char*) yajl_get_error(handle, 0, NULL, 0); ERL_NIF_TERM errMsg; if(yajlError != NULL) { errMsg = enif_make_string(env, yajlError, ERL_NIF_LATIN1); yajl_free_error(handle, (unsigned char*) yajlError); } else { errMsg = enif_make_string(env, "unknown parse error", ERL_NIF_LATIN1); } return enif_make_tuple(env, 2, enif_make_atom(env, "error"), enif_make_tuple(env, 2, enif_make_uint(env, handle->bytesConsumed), errMsg ) ); }
static ERL_NIF_TERM new_parser(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { XML_Parser parser; expat_parser *parser_data = (expat_parser *)enif_alloc(sizeof(expat_parser)); ERL_NIF_TERM parser_resource; parser = XML_ParserCreate_MM("UTF-8", &ms, "\n"); parser_data->env = env; parser_data->xmlns = enif_make_list(env, 0); init_parser(parser, parser_data); XML_Parser *xml_parser = (XML_Parser *)enif_alloc_resource(PARSER_POINTER, sizeof(XML_Parser)); *xml_parser = parser; parser_resource = enif_make_resource(env, (void *)xml_parser); enif_release_resource(xml_parser); return enif_make_tuple(env, 2, OK, parser_resource); };
static int enc_map_to_ejson(ErlNifEnv* env, ERL_NIF_TERM map, ERL_NIF_TERM* out) { ErlNifMapIterator iter; size_t size; ERL_NIF_TERM list; ERL_NIF_TERM tuple; ERL_NIF_TERM key; ERL_NIF_TERM val; if(!enif_get_map_size(env, map, &size)) { fprintf(stderr, "bad map size\r\n"); return 0; } list = enif_make_list(env, 0); if(size == 0) { *out = enif_make_list_cell(env, enif_make_tuple(env, 0), list); return 1; } if(!enif_map_iterator_create(env, map, &iter, ERL_NIF_MAP_ITERATOR_HEAD)) { fprintf(stderr, "bad iterator create\r\n"); return 0; } do { if(!enif_map_iterator_get_pair(env, &iter, &key, &val)) { fprintf(stderr, "bad get pair\r\n"); return 0; } tuple = enif_make_tuple2(env, key, val); list = enif_make_list_cell(env, tuple, list); } while(enif_map_iterator_next(env, &iter)); *out = list; return 1; }
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; }
ERL_NIF_TERM mk_error(ErlNifEnv* env, const char* mesg) { return enif_make_tuple(env, mk_atom(env, "error"), mk_atom(env, mesg)); }
ERL_NIF_TERM reverse_tokens(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { decode_ctx ctx; yajl_parser_config conf = {0, 1}; // No comments, check utf8 yajl_handle handle = yajl_alloc(&decoder_callbacks, &conf, NULL, &ctx); yajl_status status; unsigned int used; ErlNifBinary bin; ERL_NIF_TERM ret; ctx.env = env; ctx.head = enif_make_list_from_array(env, NULL, 0); if(!enif_inspect_iolist_as_binary(env, argv[0], &bin)) { ret = enif_make_badarg(env); goto done; } status = yajl_parse(handle, bin.data, bin.size); used = handle->bytesConsumed; // Parsing something like "2.0" (without quotes) will // cause a spurious semi-error. We add the extra size // check so that "2008-20-10" doesn't pass. if(status == yajl_status_insufficient_data && used == bin.size) { status = yajl_parse_complete(handle); } if(status == yajl_status_ok && used != bin.size) { if(check_rest(bin.data, bin.size, used) == CANCEL) { ret = enif_make_tuple(env, 2, enif_make_atom(env, "error"), enif_make_atom(env, "garbage_after_value") ); goto done; } } switch(status) { case yajl_status_ok: ret = enif_make_tuple(env, 2, enif_make_atom(env, "ok"), ctx.head); goto done; case yajl_status_error: ret = make_error(handle, env); goto done; case yajl_status_insufficient_data: ret = enif_make_tuple(env, 2, enif_make_atom(env, "error"), enif_make_atom(env, "insufficient_data") ); goto done; case yajl_status_client_canceled: /* the only time we do this is when we can't allocate a binary. */ ret = enif_make_tuple(env, 2, enif_make_atom(env, "error"), enif_make_atom(env, "insufficient_memory") ); goto done; default: ret = enif_make_tuple(env, 2, enif_make_atom(env, "error"), enif_make_atom(env, "unknown") ); goto done; } done: if(handle != NULL) yajl_free(handle); return ret; }
ERL_NIF_TERM _hi_next(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { hi_ctx_t* ctx = NULL; ErlNifResourceType* ctx_type = get_hi_ctx_type(env); if (argc != 1 || ctx_type == NULL || !enif_get_resource(env, argv[0], ctx_type, (void **)&ctx)) { return enif_make_badarg(env); } if (ctx != NULL && ctx->type == HDR_ITER_REC) { // skip until first non-zero index bool has_next = false; while (ctx->iter != NULL && (has_next = hdr_recorded_iter_next(ctx->iter))) { struct hdr_recorded_iter* x = ((struct hdr_recorded_iter*)ctx->iter); struct hdr_iter iter = x->iter; if (0 != iter.count_at_index) { int64_t stp = x->count_added_in_this_iteration_step; int32_t bdx = iter.bucket_index; int64_t sdx = iter.sub_bucket_index; int64_t val = iter.value_from_index; int64_t cat = iter.count_at_index; int64_t cto = iter.count_to_index; int64_t heq = iter.highest_equivalent_value; return enif_make_tuple2(env, ATOM_RECORD, enif_make_list(env, 7, enif_make_tuple2(env, ATOM_BUCKET_IDX, enif_make_int(env,bdx)), enif_make_tuple2(env, ATOM_SUB_BUCKET_IDX, enif_make_long(env,sdx)), enif_make_tuple2(env, ATOM_VAL_FROM_IDX, enif_make_long(env,val)), enif_make_tuple2(env, ATOM_VAL_AT_IDX, enif_make_long(env,cat)), enif_make_tuple2(env, ATOM_COUNT_AT_IDX, enif_make_long(env,cto)), enif_make_tuple2(env, ATOM_HIGHEST_EQUIV_VAL, enif_make_long(env,heq)), enif_make_tuple2(env, ATOM_STEP_COUNT, enif_make_long(env,stp)))); } } } if (ctx != NULL && ctx->type == HDR_ITER_LIN) { // skip until first non-zero index bool has_next = false; while (ctx->iter != NULL && (has_next = hdr_linear_iter_next(ctx->iter))) { struct hdr_linear_iter* x = ((struct hdr_linear_iter*)ctx->iter); struct hdr_iter iter = x->iter; if (0 != iter.count_at_index) { int64_t stp = x->count_added_in_this_iteration_step; int32_t vub = x->value_units_per_bucket; int64_t nvl = x->next_value_reporting_level; int64_t nve = x->next_value_reporting_level_lowest_equivalent; int32_t bdx = iter.bucket_index; int64_t sdx = iter.sub_bucket_index; int64_t val = iter.value_from_index; int64_t cat = iter.count_at_index; int64_t cto = iter.count_to_index; int64_t heq = iter.highest_equivalent_value; return enif_make_tuple2(env, ATOM_LINEAR, enif_make_list(env, 10, enif_make_tuple2(env, ATOM_BUCKET_IDX, enif_make_int(env,bdx)), enif_make_tuple2(env, ATOM_SUB_BUCKET_IDX, enif_make_long(env,sdx)), enif_make_tuple2(env, ATOM_VAL_FROM_IDX, enif_make_long(env,val)), enif_make_tuple2(env, ATOM_VAL_AT_IDX, enif_make_long(env,cat)), enif_make_tuple2(env, ATOM_COUNT_AT_IDX, enif_make_long(env,cto)), enif_make_tuple2(env, ATOM_HIGHEST_EQUIV_VAL, enif_make_long(env,heq)), enif_make_tuple2(env, ATOM_VAL_UNITS_PER_BUCKET, enif_make_int(env,vub)), enif_make_tuple2(env, ATOM_STEP_COUNT, enif_make_long(env,stp)), enif_make_tuple2(env, ATOM_NEXT_VAL_REP_LVL, enif_make_long(env,nvl)), enif_make_tuple2(env, ATOM_NEXT_VAL_REP_LVL_LOW_EQUIV, enif_make_long(env,nve)))); } } } if (ctx != NULL && ctx->type == HDR_ITER_LOG) { // skip until first non-zero index bool has_next = false; while (ctx->iter != NULL && (has_next = hdr_log_iter_next(ctx->iter))) { struct hdr_log_iter* x = (struct hdr_log_iter*)ctx->iter; struct hdr_iter iter = x->iter; if (0 != iter.count_at_index) { int64_t stp = x->count_added_in_this_iteration_step; int32_t vfb = x->value_units_first_bucket; double lgb = x->log_base; int64_t nvl = x->next_value_reporting_level; int64_t nve = x->next_value_reporting_level_lowest_equivalent; int32_t bdx = iter.bucket_index; int64_t sdx = iter.sub_bucket_index; int64_t val = iter.value_from_index; int64_t cat = iter.count_at_index; int64_t cto = iter.count_to_index; int64_t heq = iter.highest_equivalent_value; return enif_make_tuple2(env, ATOM_LOGARITHMIC, enif_make_list(env, 11, enif_make_tuple2(env, ATOM_BUCKET_IDX, enif_make_int(env,bdx)), enif_make_tuple2(env, ATOM_SUB_BUCKET_IDX, enif_make_long(env,sdx)), enif_make_tuple2(env, ATOM_VAL_FROM_IDX, enif_make_long(env,val)), enif_make_tuple2(env, ATOM_VAL_AT_IDX, enif_make_long(env,cat)), enif_make_tuple2(env, ATOM_COUNT_AT_IDX, enif_make_long(env,cto)), enif_make_tuple2(env, ATOM_HIGHEST_EQUIV_VAL, enif_make_long(env,heq)), enif_make_tuple2(env, ATOM_VAL_UNITS_FIRST_BUCKET, enif_make_int(env,vfb)), enif_make_tuple2(env, ATOM_STEP_COUNT, enif_make_long(env,stp)), enif_make_tuple2(env, ATOM_LOG_BASE, enif_make_double(env,lgb)), enif_make_tuple2(env, ATOM_NEXT_VAL_REP_LVL, enif_make_long(env,nvl)), enif_make_tuple2(env, ATOM_NEXT_VAL_REP_LVL_LOW_EQUIV, enif_make_long(env,nve)))); } } } if (ctx != NULL && ctx->type == HDR_ITER_PCT) { // skip until first non-zero index bool has_next = false; while (ctx->iter != NULL && (has_next = hdr_percentile_iter_next(ctx->iter))) { struct hdr_percentile_iter* x = (struct hdr_percentile_iter*)ctx->iter; struct hdr_iter iter = x->iter; if (0 != iter.count_at_index) { bool slv = x->seen_last_value; int32_t tph = x->ticks_per_half_distance; double pti = x->percentile_to_iterate_to; double pct = x->percentile; int32_t bdx = iter.bucket_index; int64_t sdx = iter.sub_bucket_index; int64_t val = iter.value_from_index; int64_t cat = iter.count_at_index; int64_t cto = iter.count_to_index; int64_t heq = iter.highest_equivalent_value; return enif_make_tuple2(env, ATOM_PERCENTILE, enif_make_list(env, 10, enif_make_tuple2(env, ATOM_BUCKET_IDX, enif_make_int(env,bdx)), enif_make_tuple2(env, ATOM_SUB_BUCKET_IDX, enif_make_long(env,sdx)), enif_make_tuple2(env, ATOM_VAL_FROM_IDX, enif_make_long(env,val)), enif_make_tuple2(env, ATOM_VAL_AT_IDX, enif_make_long(env,cat)), enif_make_tuple2(env, ATOM_COUNT_AT_IDX, enif_make_long(env,cto)), enif_make_tuple2(env, ATOM_HIGHEST_EQUIV_VAL, enif_make_long(env,heq)), enif_make_tuple2(env, ATOM_SEEN_LAST_VAL, enif_make_atom(env,slv ? "true" : "false")), enif_make_tuple2(env, ATOM_PERCENTILE_TO_ITERATE_TO, enif_make_double(env,pti)), enif_make_tuple2(env, ATOM_PERCENTILE, enif_make_double(env,pct)), enif_make_tuple2(env, ATOM_TICKS_PER_HALF_DISTANCE, enif_make_int(env,tph)))); } } } return enif_make_tuple2( env, ATOM_FALSE, enif_make_tuple(env,0) ); }
ERL_NIF_TERM json_encode(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { Encoder enc; yajl_gen_config config = {0, NULL}; yajl_gen handle = yajl_gen_alloc(&config, NULL); yajl_gen_status status; ERL_NIF_TERM ret = enif_make_badarg(env); ErlNifBinary bin; const unsigned char* json; unsigned int jsonlen; if(argc != 1) goto done; if(handle == NULL) { ret = enif_make_tuple(env, 2, enif_make_atom(env, "error"), enif_make_atom(env, "memory_error") ); goto done; } enc.env = env; enc.handle = handle; enc.error = 0; if(enc_json(&enc, argv[0]) == ERROR) { if(enc.error == 0) { ret = enif_make_atom(env, "unknown"); } else { ret = enc.error; } ret = enif_make_tuple(env, 2, enif_make_atom(env, "error"), ret ); goto done; } status = yajl_gen_get_buf(handle, &json, &jsonlen); if(status != yajl_gen_status_ok) { ret = enif_make_tuple(env, 2, enif_make_atom(env, "error"), enif_make_atom(env, "unknown") ); goto done; } if(!enif_alloc_binary_compat(env, jsonlen, &bin)) { ret = enif_make_atom(env, "memory_error"); goto done; } memcpy(bin.data, json, jsonlen); ret = enif_make_tuple(env, 2, enif_make_atom(env, "ok"), enif_make_binary(env, &bin) ); done: if(handle != NULL) yajl_gen_free(handle); return ret; }
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; }