static int prefix_cb(void *data, const unsigned char *k, uint32_t k_len, void *val) { callback_data *cb_data = data; art_elem_struct *elem = val; ErlNifBinary key, value; enif_alloc_binary(k_len - 1, &key); memcpy(key.data, k, k_len - 1); enif_alloc_binary(elem->size, &value); memcpy(value.data, elem->data, elem->size); ErlNifEnv *msg_env = enif_alloc_env(); if(msg_env == NULL) return mk_error(cb_data->env, "env_alloc_error");; ERL_NIF_TERM caller_ref = enif_make_copy(msg_env, cb_data->caller_ref); ERL_NIF_TERM res = enif_make_tuple2(msg_env, caller_ref, enif_make_tuple2(msg_env, enif_make_binary(msg_env, &key), enif_make_binary(msg_env, &value))); if(!enif_send(cb_data->env, &cb_data->pid, msg_env, res)) { enif_free(msg_env); return -1; } enif_free(msg_env); return 0; }
void secfile_t::read_newline() { if(*get_next_line()) { throw mk_error("Expected newline"); } ++line; }
static ERL_NIF_TERM elibart_prefix_search(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { art_tree* t; ErlNifBinary key; callback_data cb_data; // extract arguments atr_tree, key if (argc != 4) return enif_make_badarg(env); if(!enif_get_resource(env, argv[0], elibart_RESOURCE, (void**) &t)) return enif_make_badarg(env); if (!enif_inspect_binary(env, argv[1], &key)) return enif_make_badarg(env); cb_data.env = env; if(!enif_is_pid(env, argv[3])) return mk_error(env, "not_a_pid"); if(!enif_get_local_pid(env, argv[3], &cb_data.pid)) return mk_error(env, "not_a_local_pid"); cb_data.caller_ref = argv[2]; // TODO this should be a worker thread since it's a long opearation (?) if (art_iter_prefix(t, key.data, key.size, prefix_cb, &cb_data)) return mk_error(env, "art_prefix_search"); ErlNifEnv *msg_env = enif_alloc_env(); if(msg_env == NULL) return mk_error(env, "env_alloc_error");; ERL_NIF_TERM caller_ref = enif_make_copy(msg_env, argv[2]); ERL_NIF_TERM res = enif_make_tuple2(msg_env, caller_ref, mk_atom(msg_env, "ok")); if (!enif_send(env, &cb_data.pid, msg_env, res)) { enif_free(msg_env); return mk_error(env, "art_prefix_search"); } enif_free(msg_env); return mk_atom(env, "ok"); }
static ERL_NIF_TERM elibart_insert(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { art_tree* t; ErlNifBinary key, value; art_elem_struct *elem; unsigned char buffer[BUFF_SIZE]; // 256Kb buffer unsigned char *key_copy = buffer; // extract arguments atr_tree, key, value if (argc != 3) return enif_make_badarg(env); if(!enif_get_resource(env, argv[0], elibart_RESOURCE, (void**) &t)) return enif_make_badarg(env); if (!enif_inspect_binary(env, argv[1], &key)) return enif_make_badarg(env); if (!enif_inspect_binary(env, argv[2], &value)) return enif_make_badarg(env); // buffer size not enough, pay the price if (key.size > BUFF_SIZE) key_copy = malloc(key.size + 1); // TODO review -- is it possible not to copy the key just to add '\0'? memcpy(key_copy, key.data, key.size); key_copy[key.size] = '\0'; //create art element elem = malloc(sizeof(art_elem_struct)); if (elem == NULL) mk_error(env, "malloc_no_mem"); elem->data = malloc(value.size); elem->size = value.size; memcpy(elem->data, value.data, value.size); // insert the element in the art_tree art_elem_struct *old_elem = art_insert(t, key_copy, key.size + 1, elem); // buffer size not enough, pay the price if (key.size > BUFF_SIZE) free(key_copy); // the inserted key is new if (!old_elem) return enif_make_tuple2(env, mk_atom(env, "ok"), mk_atom(env, "empty")); // the inserted key already existed, return previous value ErlNifBinary res; enif_alloc_binary(old_elem->size, &res); memcpy(res.data, old_elem->data, old_elem->size); free(old_elem->data); free(old_elem); return enif_make_tuple2(env, enif_make_atom(env, "ok"), enif_make_binary(env, &res)); }
static ERL_NIF_TERM elibart_new(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { art_tree* t = enif_alloc_resource(elibart_RESOURCE, sizeof(art_tree)); if (init_art_tree(t) != 0) return mk_error(env, "init_art_tree"); else { ERL_NIF_TERM res = enif_make_resource(env, t); enif_release_resource(t); return enif_make_tuple2(env, mk_atom(env, "ok"), res); } }
static ERL_NIF_TERM elibart_destroy(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { art_tree *t; if (argc != 1) return enif_make_badarg(env); if(!enif_get_resource(env, argv[0], elibart_RESOURCE, (void**) &t)) return enif_make_badarg(env); art_iter(t, delete_cb, NULL); if (destroy_art_tree((art_tree*) argv[0]) != 0) return mk_error(env, "destroy_art_tree"); return mk_atom(env, "ok"); }
static ERL_NIF_TERM delta_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { state_t *state = NULL; rs_result res; if (!enif_get_resource(env, argv[0], state_r, (void *) &state)) return enif_make_badarg(env); if (state->type != LOADSIG) return enif_make_badarg(env); res = rs_build_hash_table(state->sig); if (res != RS_DONE) return mk_error(env, res); if (state->job) rs_job_free(state->job); state->job = rs_delta_begin(state->sig); state->in_size = 0; state->out_size = 0; state->type = DELTA; return enif_make_atom(env, "ok"); }
sexpr_t* eval(sexpr_t* sexpr, sexpr_t** env, sexpr_list_t* roots, error_t** error) { if(sexpr == NULL) { return interp.nil_sym; } /* printf("[eval]\n"); */ /* print_sexpr(sexpr); */ /* printf("\n"); */ roots = cons_to_roots_list(roots, sexpr); gc_collect(roots); if(ATOM(sexpr)) { if(SYM(sexpr)) { if(interp.t_sym == sexpr) { return interp.t_sym; } if(interp.nil_sym == sexpr) { return interp.nil_sym; } sexpr_t* val = assoc(sexpr, *env); if(val == NULL) { *error = mk_error("Undefined symbol", SYM_VAL(sexpr)); } return val; } if(INT(sexpr)) { return sexpr; } } else if(ATOM(CAR(sexpr))) { if(SYM(CAR(sexpr))) { // quote if(interp.quote_sym == CAR(sexpr)) { if(CDR(sexpr) == NULL) { *error = mk_error("Missing quote argument", ""); return NULL; } if(CDR(CDR(sexpr)) != NULL) { *error = mk_error("Too many arguments for quote", ""); return NULL; } return CAR(CDR(sexpr)); } // atom if(interp.atom_sym == CAR(sexpr)) { if(ATOM(eval(CAR(CDR(sexpr)), env, roots, error))) { return interp.t_sym; } return interp.nil_sym; } // eq if(interp.eq_sym == CAR(sexpr)) { // TODO check nb args sexpr_t* e1 = eval(CAR(CDR(sexpr)), env, roots, error); if(*error != NULL) { return NULL; } roots = cons_to_roots_list(roots, e1); sexpr_t* e2 = eval(CAR(CDR(CDR(sexpr))), env, roots, error); if(*error != NULL) { return NULL; } if(INT(e1) && INT(e2)) { if(INT_VAL(e1) == INT_VAL(e2)) { return interp.t_sym; } return interp.nil_sym; } if(e1 == e2) { return interp.t_sym; } return interp.nil_sym; } // if if(interp.if_sym == CAR(sexpr)) { sexpr_t* e1 = eval(CAR(CDR(sexpr)), env, roots, error); if(*error != NULL) { return NULL; } if(e1 == interp.nil_sym) { return eval(CAR(CDR(CDR(CDR(sexpr)))), env, roots, error); } else { return eval(CAR(CDR(CDR(sexpr))), env, roots, error); } } // car if(interp.car_sym == CAR(sexpr)) { sexpr_t* e1 = eval(CAR(CDR(sexpr)), env, roots, error); if(*error != NULL) { return NULL; } if(e1 == interp.nil_sym) { return interp.nil_sym; } return CAR(e1); } // cdr if(interp.cdr_sym == CAR(sexpr)) { sexpr_t* e1 = eval(CAR(CDR(sexpr)), env, roots, error); if(*error != NULL) { return NULL; } if(e1 == interp.nil_sym) { return interp.nil_sym; } sexpr_t *res = CDR(e1); if(res == NULL) { return interp.nil_sym; } return res; } // + if(interp.plus_sym == CAR(sexpr)) { sexpr_t* e1 = eval(CAR(CDR(sexpr)), env, roots, error); if(*error != NULL) { return NULL; } roots = cons_to_roots_list(roots, e1); sexpr_t* e2 = eval(CAR(CDR(CDR(sexpr))), env, roots, error); if(*error != NULL) { return NULL; } if(INT(e1) && INT(e2)) { return mk_int(INT_VAL(e1) + INT_VAL(e2)); } *error = mk_error("Arguments for '+' are not integers", ""); return NULL; } // - if(interp.minus_sym == CAR(sexpr)) { sexpr_t* e1 = eval(CAR(CDR(sexpr)), env, roots, error); if(*error != NULL) { return NULL; } roots = cons_to_roots_list(roots, e1); sexpr_t* e2 = eval(CAR(CDR(CDR(sexpr))), env, roots, error); if(*error != NULL) { return NULL; } if(INT(e1) && INT(e2)) { return mk_int(INT_VAL(e1) - INT_VAL(e2)); } *error = mk_error("Arguments for '-' are not integers", ""); return NULL; } if(interp.mul_sym == CAR(sexpr)) { sexpr_t* e1 = eval(CAR(CDR(sexpr)), env, roots, error); if(*error != NULL) { return NULL; } roots = cons_to_roots_list(roots, sexpr); sexpr_t* e2 = eval(CAR(CDR(CDR(sexpr))), env, roots, error); if(*error != NULL) { return NULL; } if(INT(e1) && INT(e2)) { return mk_int(INT_VAL(e1) * INT_VAL(e2)); } *error = mk_error("Arguments for '*' are not integers", ""); return NULL; } // cons if(interp.cons_sym == CAR(sexpr)) { sexpr_t* e1 = eval(CAR(CDR(sexpr)), env, roots, error); if(*error != NULL) { return NULL; } roots = cons_to_roots_list(roots, e1); sexpr_t* e2 = eval(CAR(CDR(CDR(sexpr))), env, roots, error); if(*error != NULL) { return NULL; } return mk_cons(e1 == interp.nil_sym ? NULL : e1, e2 == interp.nil_sym ? NULL : e2); } // def if(interp.def_sym == CAR(sexpr)) { sexpr_t* arg = CAR(CDR(CDR(sexpr))); roots = cons_to_roots_list(roots, arg); sexpr_t* val = eval(arg, env, roots, error); if(*error != NULL) { return NULL; } *env = mk_cons(mk_cons(intern(SYM_VAL(CAR(CDR(sexpr)))), val), *env); return val; } // print if(interp.print_sym == CAR(sexpr)) { sexpr_t* e1 = eval(CAR(CDR(sexpr)), env, roots, error); if(*error != NULL) { return NULL; } print_sexpr(e1); printf("\n"); return e1; } // fn if(interp.fn_sym == CAR(sexpr)) { return mk_fn(sexpr, *env); } // macro if(interp.macro_sym == CAR(sexpr)) { return mk_macro(sexpr); } //eval if(interp.eval_sym == CAR(sexpr)) { sexpr_t* e1 = eval(CAR(CDR(sexpr)), env, roots, error); if(*error != NULL) { return NULL; } roots = cons_to_roots_list(roots, e1); return eval(e1, env, roots, error); } // else resolves first variable sexpr_t* fn = eval(CAR(sexpr), env, roots, error); if(*error != NULL) { return NULL; } // eval fn if(FN(fn)) { sexpr_t* fn_code = CAR(CDR(CDR(CAR(fn)))); sexpr_t* captured_env = CDR(fn); sexpr_t* arguments = eval_list(CDR(sexpr), env, roots, error); if(*error != NULL) { return NULL; } sexpr_t* pairs = pair(CAR(CDR(CAR(fn))), arguments); sexpr_t* eval_env = append(pairs, captured_env); // append the function itself to the env, roots, for recursive calls eval_env = mk_cons(mk_cons(CAR(sexpr), fn), eval_env); /* printf("fn code=\n"); */ /* print_sexpr(fn_code); */ /* printf("\n"); */ roots = cons_to_roots_list(roots, eval_env); return eval(fn_code, &eval_env, roots, error); } // eval macro if(MACRO(fn)) { sexpr_t* macro_code = CAR(CDR(CDR(CAR(fn)))); sexpr_t* pairs = pair(CAR(CDR(CAR(fn))), CDR(sexpr)); sexpr_t* eval_env = append(pairs, *env); roots = cons_to_roots_list(roots, eval_env); sexpr_t* transformed_code = eval(macro_code, &eval_env, roots, error); if(*error != NULL) { return NULL; } return eval(transformed_code, env, roots, error); } // else primitives sexpr_t* arguments = eval_list(CDR(sexpr), env, roots, error); if(*error != NULL) { return NULL; } sexpr_t* to_eval = mk_cons(fn, arguments); return eval(to_eval, env, roots, error); } } else if(CAR(CAR(sexpr)) == interp.fn_sym) { // executes an anonymous function sexpr_t* fn = CAR(sexpr); sexpr_t* fn_code = CAR(CDR(CDR(fn))); sexpr_t* arguments = eval_list(CDR(sexpr), env, roots, error); if(*error != NULL) { return NULL; } sexpr_t* l = pair(CAR(CDR(fn)), arguments); l = append(l, *env); roots = cons_to_roots_list(roots, l); return eval(fn_code, &l, roots, error); } print_sexpr(sexpr); printf("\n"); *error = mk_error("Invalid expression", ""); return NULL; }
static ERL_NIF_TERM do_job(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { state_t *state = NULL; ErlNifBinary input; size_t block_size; int is_eof; size_t input_size; char *input_data; rs_result res; if (!enif_get_resource(env, argv[0], state_r, (void *) &state)) return enif_make_badarg(env); if (argc == 1) { is_eof = 1; input_size = 0; input_data = NULL; } else { if (!enif_inspect_iolist_as_binary(env, argv[1], &input)) return enif_make_badarg(env); is_eof = 0; input_size = input.size; input_data = (char *) input.data; } block_size = MAX(state->in_size + input_size, RS_JOB_BLOCKSIZE); if (input_size) { state->in = realloc(state->in, state->in_size + input_size); memcpy(state->in + state->in_size, input_data, input_size); } state->in_size += input_size; state->out_size = 0; while (1) { state->out = realloc(state->out, state->out_size + block_size); rs_buffers_t buf = {.next_in = state->in, .avail_in = state->in_size, .eof_in = is_eof, .next_out = state->out + state->out_size, .avail_out = block_size}; res = rs_job_iter(state->job, &buf); state->in_size = buf.avail_in; state->out_size += block_size - buf.avail_out; if (res == RS_BLOCKED) { if (buf.avail_in > 0) { state->in = realloc(state->in, buf.avail_in); memcpy(state->in, buf.next_in, buf.avail_in); } if (!is_eof) return mk_output(env, state); } else if (res == RS_DONE) { return mk_output(env, state); } else { return mk_error(env, res); } } } static ERL_NIF_TERM job_iter(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { return do_job(env, argc, argv); } static ERL_NIF_TERM job_done(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { return do_job(env, argc, argv); } static ErlNifFunc nif_funcs[] = { {"sig_init", 0, sig_init}, {"loadsig_init", 0, loadsig_init}, {"delta_init", 1, delta_init}, {"patch_init", 1, patch_init}, {"format_error_nif", 1, format_error}, {"job_iter", 2, job_iter}, {"job_done", 1, job_done} }; ERL_NIF_INIT(rsync, nif_funcs, load, NULL, NULL, NULL)