int array_setrange(stk_array **harr, array_iter *start, stk_array *inarr) { stk_array *arr; array_iter idx; if (!harr || !*harr) { return -1; } arr = *harr; if (!inarr || !inarr->items) { return arr->items; } switch (arr->type) { case ARRAY_PACKED:{ if (!start) { return -1; } if (start->type != PROG_INTEGER) { return -1; } if (start->data.number < 0 || start->data.number > arr->items) { return -1; } if (arr->links > 1 && !arr->pinned) { arr->links--; arr = *harr = array_decouple(arr); } if (array_first(inarr, &idx)) { do { array_setitem(&arr, start, array_getitem(inarr, &idx)); start->data.number++; } while (array_next(inarr, &idx)); } return arr->items; break; } case ARRAY_DICTIONARY:{ if (arr->links > 1 && !arr->pinned) { arr->links--; arr = *harr = array_decouple(arr); } if (array_first(inarr, &idx)) { do { array_setitem(&arr, &idx, array_getitem(inarr, &idx)); } while (array_next(inarr, &idx)); } return arr->items; break; } default: break; } return -1; }
/*\ |*| array_mash |*| Takes the lists of values from the first array and |*| uses each value as a key in the second array. For |*| each key, the passed "change_by" value is applied to |*| any existing value. If the value does not exist, it |*| is set. |*| This will be the core of the different/union/intersection |*| code. |*| Of course, this is going to absolutely blow chunks when |*| passed an array with value types that can't be used as |*| key values in an array. Blast. That may be infeasible |*| regardless, though. \*/ void array_mash(stk_array *arr_in, stk_array **mash, int value) { int still_values = 0; array_iter current_key; array_iter *current_keyval; array_iter *current_value; array_data temp_value; if (NULL == arr_in || NULL == mash || NULL == *mash) return; still_values = array_first(arr_in, ¤t_key); while (still_values) { current_keyval = array_getitem(arr_in, ¤t_key); current_value = array_getitem(*mash, current_keyval); if (NULL != current_value) { if (PROG_INTEGER == current_value->type) { copyinst(current_value, &temp_value); temp_value.data.number += value; array_setitem(mash, current_keyval, &temp_value); } } else { temp_value.type = PROG_INTEGER; temp_value.data.number = value; array_insertitem(mash, current_keyval, &temp_value); } still_values = array_next(arr_in, ¤t_key); } }
/*\ |*| array_demote_only |*| array demote discards the values of a dictionary, and |*| returns a packed list of the keys. |*| (Useful because keys are ordered and unique, presumably.) |*| (This allows the keys to be abused as sets.) \*/ stk_array * array_demote_only(stk_array *arr, int threshold) { stk_array *demoted_array = NULL; int items_left = 0; array_iter current_key; array_iter *current_value; array_iter new_index; if (!arr || ARRAY_DICTIONARY != arr->type) return NULL; new_index.type = PROG_INTEGER;; new_index.data.number = 0; demoted_array = new_array_packed(0); items_left = array_first(arr, ¤t_key); while (items_left) { current_value = array_getitem(arr, ¤t_key); if (PROG_INTEGER == current_value->type && current_value->data.number >= threshold) { array_insertitem(&demoted_array, &new_index, ¤t_key); new_index.data.number++; } items_left = array_next(arr, ¤t_key); } return demoted_array; }
void prim_foriter(PRIM_PROTOTYPE) { CHECKOP(0); if (!fr->fors.st) abort_interp("Internal error; FOR stack underflow."); if (fr->fors.st->end.type == PROG_ARRAY) { stk_array *arr = fr->fors.st->end.data.array; if (fr->fors.st->didfirst) { result = array_next(arr, &fr->fors.st->cur); } else { result = array_first(arr, &fr->fors.st->cur); fr->fors.st->didfirst = 1; } if (result) { array_data *val = array_getitem(arr, &fr->fors.st->cur); if (val) { CHECKOFLOW(2); PushInst(&fr->fors.st->cur); /* push key onto stack */ PushInst(val); /* push value onto stack */ tmp = 1; /* tell following IF to NOT branch out of loop */ } else { tmp = 0; /* tell following IF to branch out of loop */ } } else { fr->fors.st->cur.type = PROG_INTEGER; fr->fors.st->cur.line = 0; fr->fors.st->cur.data.number = 0; tmp = 0; /* tell following IF to branch out of loop */ } } else { int cur = fr->fors.st->cur.data.number; int end = fr->fors.st->end.data.number; tmp = fr->fors.st->step > 0; if (tmp) tmp = !(cur > end); else tmp = !(cur < end); if (tmp) { CHECKOFLOW(1); result = cur; fr->fors.st->cur.data.number += fr->fors.st->step; PushInt(result); } } CHECKOFLOW(1); PushInt(tmp); }
static int run02(UNUSED int argc, UNUSED void **argv) { mnbytes_t **s; mnarray_iter_t it; for (s = array_first(&files, &it); s != NULL; s = array_next(&files, &it)) { //CTRACE("file: %s", BDATA(*s)); MRKTHR_SPAWN("run11", run11, *s); } return 0; }
/** * Convert array to string. We separate keys with 0x1 and values with 0x2 */ int array_serialize( struct array_t *arr, char **outs ) { node *n; int count = 0; char *str = 0; for( n=array_first( arr ); n != NULL; n = array_next( arr ) ) { str = *outs; /* Not portable but my world always involves GNU or FreeBSD */ count = asprintf( outs, "%s%s\1%s\2", str == NULL ? "" : str, n->key, n->value ); if( str ) free(str); } return count; }
int array_is_homogenous(stk_array *arr, int typ) { array_iter idx; array_data *dat; int failedflag = 0; if (array_first(arr, &idx)) { do { dat = array_getitem(arr, &idx); if (dat->type != typ) { failedflag = 1; } } while (array_next(arr, &idx)); } return (!failedflag); }
stk_array * array_decouple(stk_array *arr) { stk_array *new2; if (!arr) { return NULL; } new2 = new_array(); new2->pinned = arr->pinned; new2->type = arr->type; switch (arr->type) { case ARRAY_PACKED:{ int i; new2->items = arr->items; new2->data.packed = (array_data *) malloc(sizeof(array_data) * arr->items); for (i = arr->items; i-- > 0;) { copyinst(&arr->data.packed[i], &new2->data.packed[i]); } return new2; break; } case ARRAY_DICTIONARY:{ array_iter idx; array_data *val; if (array_first(arr, &idx)) { do { val = array_getitem(arr, &idx); array_setitem(&new2, &idx, val); } while (array_next(arr, &idx)); } return new2; break; } default: break; } return NULL; }
/** * Load, parse, evaulate, display, with a form */ void template_run_form( char *path, struct form_t *form, struct array_t *them ) { struct array_t *arr = array_new(); node *n; /* If not empty we validated */ if( ! array_empty( form->err) ) { array_add_obj( arr, "errors", form->err ); } for( n=array_first( form->clean ); n != NULL; n = array_next( form->clean ) ) { // printf("F**K %s %s\n", n->key, n->value ); array_add_str( arr, n->key, nully(n->value) ); } template_run( path, arr ); array_free(arr); }
void main() { struct array_t *arr = array_new(); int k=0; char *out=NULL; struct array_t *arr2 = array_new(); node *n; for(k=0; k<10; k++ ) { array_add_str( arr, "k", "v" ); } k=array_serialize( arr, &out ); printf("%d %s \n", k, out ); array_deserialize( arr2, out ); for( n=array_first(arr2); n!=NULL; n = array_next(arr2)) { printf("%s %s\n", n->key, n->value ); } free(out); array_free( arr); array_free( arr2); }
void prim_array_regsub(PRIM_PROTOTYPE) { struct inst *in; stk_array *arr; stk_array *nw; int matches[MATCH_ARR_SIZE]; int flags = 0; char* write_ptr = buf; int write_left = BUFFER_LEN - 1; muf_re* re; char* text; char* textstart; const char* errstr; int matchcnt, len; CHECKOP(4); oper4 = POP(); /* int:Flags */ oper3 = POP(); /* str:Replace */ oper2 = POP(); /* str:Pattern */ oper1 = POP(); /* str:Text */ if (oper1->type != PROG_ARRAY) abort_interp("Argument not an array of strings. (1)"); if (!array_is_homogenous(oper1->data.array, PROG_STRING)) abort_interp("Argument not an array of strings. (1)"); if (oper2->type != PROG_STRING) abort_interp("Non-string argument (2)"); if (oper3->type != PROG_STRING) abort_interp("Non-string argument (3)"); if (oper4->type != PROG_INTEGER) abort_interp("Non-integer argument (4)"); if (!oper2->data.string) abort_interp("Empty string argument (2)"); if (oper4->data.number & MUF_RE_ICASE) flags |= PCRE_CASELESS; if (oper4->data.number & MUF_RE_EXTENDED) flags |= PCRE_EXTENDED; if ((re = muf_re_get(oper2->data.string, flags, &errstr)) == NULL) abort_interp(errstr); nw = new_array_dictionary(); arr = oper1->data.array; if (!re->extra && ((oper4->data.number & MUF_RE_ALL ) || array_count(arr) > 2)) { /* Study the pattern if the user requested recursive substitution, or * if the input array contains at least three items. */ re->extra = pcre_study(re->re, 0, &errstr); if (errstr) abort_interp(errstr); } if (array_first(arr, &temp1)) { do { write_ptr = buf; write_left = BUFFER_LEN - 1; in = array_getitem(arr, &temp1); textstart = text = (char *)DoNullInd(in->data.string); len = strlen(textstart); while((*text != '\0') && (write_left > 0)) { if ((matchcnt = pcre_exec(re->re, re->extra, textstart, len, text-textstart, 0, matches, MATCH_ARR_SIZE)) < 0) { if (matchcnt != PCRE_ERROR_NOMATCH) { abort_interp(muf_re_error(matchcnt)); } while((write_left > 0) && (*text != '\0')) { *write_ptr++ = *text++; write_left--; } break; } else { int allstart = matches[0]; int allend = matches[1]; int substart = -1; int subend = -1; char* read_ptr = (char *)DoNullInd(oper3->data.string); int count; for(count = allstart-(text-textstart); (write_left > 0) && (*text != '\0') && (count > 0); count--) { *write_ptr++ = *text++; write_left--; } while((write_left > 0) && (*read_ptr != '\0')) { if (*read_ptr == '\\') { if (!isdigit(*(++read_ptr))) { *write_ptr++ = *read_ptr++; write_left--; } else { int idx = (*read_ptr++) - '0'; if ((idx < 0) || (idx >= matchcnt)) { abort_interp("Invalid \\subexp in substitution string. (3)"); } substart = matches[idx*2]; subend = matches[idx*2+1]; if ((substart >= 0) && (subend >= 0) && (substart < len)) { char* ptr = &textstart[substart]; count = subend - substart; if (count > write_left) { abort_interp("Operation would result in overflow"); } for(; (write_left > 0) && (count > 0) && (*ptr != '\0'); count--) { *write_ptr++ = *ptr++; write_left--; } } } } else { *write_ptr++ = *read_ptr++; write_left--; } } for(count = allend - allstart; (*text != '\0') && (count > 0); count--) text++; if (allstart == allend && *text) { *write_ptr++ = *text++; write_left--; } } if ((oper4->data.number & MUF_RE_ALL) == 0) { while((write_left > 0) && (*text != '\0')) { *write_ptr++ = *text++; write_left--; } break; } } if (*text != '\0') abort_interp("Operation would result in overflow"); *write_ptr = '\0'; temp2.type = PROG_STRING; temp2.data.string = alloc_prog_string(buf); array_setitem(&nw, &temp1, &temp2); CLEAR(&temp2); } while (array_next(arr, &temp1)); } CLEAR(oper4); CLEAR(oper3); CLEAR(oper2); CLEAR(oper1); PushArrayRaw(nw); }
END_TEST /* * request */ START_TEST(test_quit) { #define QUIT "quit" #define SERIALIZED "*1\r\n$4\r\n" QUIT "\r\n" #define INVALID "*2\r\n$4\r\n" QUIT "\r\n$3\r\nnow\r\n" int ret; struct element *el; test_reset(); req->type = REQ_QUIT; el = array_push(req->token); el->type = ELEM_BULK; el->bstr = (struct bstring){sizeof(QUIT) - 1, QUIT}; ret = compose_req(&buf, req); ck_assert_int_eq(ret, sizeof(SERIALIZED) - 1); ck_assert_int_eq(cc_bcmp(buf->rpos, SERIALIZED, ret), 0); el->type = ELEM_UNKNOWN; /* this effectively resets *el */ request_reset(req); ck_assert_int_eq(parse_req(req, buf), PARSE_OK); ck_assert_int_eq(req->type, REQ_QUIT); ck_assert_int_eq(req->token->nelem, 1); el = array_first(req->token); ck_assert_int_eq(el->type, ELEM_BULK); ck_assert_int_eq(cc_bcmp(el->bstr.data, QUIT, sizeof(QUIT) - 1), 0); /* invalid number of arguments */ test_reset(); buf_write(buf, INVALID, sizeof(INVALID) - 1); ck_assert_int_eq(parse_req(req, buf), PARSE_EINVALID); #undef INVALID #undef SERIALIZED #undef QUIT } END_TEST START_TEST(test_ping) { #define PING "ping" #define VAL "hello" #define S_PING "*1\r\n$4\r\n" PING "\r\n" #define S_ECHO "*2\r\n$4\r\n" PING "\r\n$5\r\nhello\r\n" int ret; struct element *el; test_reset(); /* simple ping */ buf_write(buf, S_PING, sizeof(S_PING) - 1); ck_assert_int_eq(parse_req(req, buf), PARSE_OK); ck_assert_int_eq(req->type, REQ_PING); /* ping as echo */ test_reset(); req->type = REQ_PING; el = array_push(req->token); el->type = ELEM_BULK; el->bstr = (struct bstring){sizeof(PING) - 1, PING}; el = array_push(req->token); el->type = ELEM_BULK; el->bstr = (struct bstring){sizeof(VAL) - 1, VAL}; ret = compose_req(&buf, req); ck_assert_int_eq(ret, sizeof(S_ECHO) - 1); ck_assert_int_eq(cc_bcmp(buf->rpos, S_ECHO, ret), 0); el->type = ELEM_UNKNOWN; /* resets *el */ request_reset(req); ck_assert_int_eq(parse_req(req, buf), PARSE_OK); ck_assert_int_eq(req->type, REQ_PING); ck_assert_int_eq(req->token->nelem, 2); el = array_first(req->token); ck_assert_int_eq(el->type, ELEM_BULK); ck_assert_int_eq(cc_bcmp(el->bstr.data, PING, sizeof(PING) - 1), 0); el = array_get(req->token, 1); ck_assert_int_eq(el->type, ELEM_BULK); ck_assert_int_eq(cc_bcmp(el->bstr.data, VAL, sizeof(VAL) - 1), 0); #undef S_ECHO #undef ECHO #undef S_PING #undef QUIT } END_TEST START_TEST(test_unfin_req) { char *token[4] = { "*2\r\n", "*2\r\n$3\r\n", "*2\r\n$3\r\nfoo\r\n", "*2\r\n$3\r\nfoo\r\n$3\r\n", }; for (int i = 0; i < 4; i++) { char *pos; size_t len; len = strlen(token[i]); buf_reset(buf); buf_write(buf, token[i], len); pos = buf->rpos; ck_assert_int_eq(parse_req(req, buf), PARSE_EUNFIN); ck_assert(buf->rpos == pos); } } END_TEST /* * response */ START_TEST(test_ok) { #define OK "OK" #define SERIALIZED "+" OK "\r\n" int ret; struct element *el; test_reset(); rsp->type = ELEM_STR; el = array_push(rsp->token); el->type = ELEM_STR; el->bstr = (struct bstring){sizeof(OK) - 1, OK}; ret = compose_rsp(&buf, rsp); ck_assert_int_eq(ret, sizeof(SERIALIZED) - 1); ck_assert_int_eq(cc_bcmp(buf->rpos, SERIALIZED, ret), 0); el->type = ELEM_UNKNOWN; /* resets *el */ response_reset(rsp); ck_assert_int_eq(parse_rsp(rsp, buf), PARSE_OK); ck_assert_int_eq(rsp->type, ELEM_STR); ck_assert_int_eq(rsp->token->nelem, 1); el = array_first(rsp->token); ck_assert_int_eq(el->type, ELEM_STR); ck_assert_int_eq(cc_bcmp(el->bstr.data, OK, sizeof(OK) - 1), 0); #undef SERIALIZED #undef OK } END_TEST START_TEST(test_array_reply) { #define SERIALIZED "*5\r\n:-10\r\n$-1\r\n-ERR invalid arg\r\n+foo\r\n$5\r\nHELLO\r\n" size_t len = sizeof(SERIALIZED) - 1; struct element *el; test_reset(); buf_write(buf, SERIALIZED, len); ck_assert_int_eq(parse_rsp(rsp, buf), PARSE_OK); ck_assert_int_eq(rsp->type, ELEM_ARRAY); ck_assert_int_eq(rsp->token->nelem, 5); el = array_first(rsp->token); ck_assert_int_eq(el->type, ELEM_INT); el = array_get(rsp->token, 1); ck_assert_int_eq(el->type, ELEM_NIL); el = array_get(rsp->token, 2); ck_assert_int_eq(el->type, ELEM_ERR); el = array_get(rsp->token, 3); ck_assert_int_eq(el->type, ELEM_STR); el = array_get(rsp->token, 4); ck_assert_int_eq(el->type, ELEM_BULK); ck_assert_int_eq(el->bstr.len, 5); ck_assert_int_eq(cc_bcmp(el->bstr.data, "HELLO", 5), 0); ck_assert_int_eq(buf_rsize(buf), 0); ck_assert_int_eq(compose_rsp(&buf, rsp), len); ck_assert_int_eq(buf_rsize(buf), len); ck_assert_int_eq(cc_bcmp(buf->rpos, SERIALIZED, len), 0); #undef SERIALIZED } END_TEST /* * edge cases */ START_TEST(test_empty_buf) { struct element el; test_reset(); ck_assert(!token_is_array(buf)); ck_assert_int_eq(parse_element(&el, buf), PARSE_EUNFIN); ck_assert_int_eq(parse_rsp(rsp, buf), PARSE_EUNFIN); ck_assert_int_eq(parse_req(req, buf), PARSE_EUNFIN); } END_TEST /* * request/response pool */ START_TEST(test_req_pool_basic) { #define POOL_SIZE 10 int i; struct request *reqs[POOL_SIZE]; request_options_st options = { .request_ntoken = {.type = OPTION_TYPE_UINT, .val.vuint = REQ_NTOKEN}, .request_poolsize = {.type = OPTION_TYPE_UINT, .val.vuint = POOL_SIZE}}; request_setup(&options, NULL); for (i = 0; i < POOL_SIZE; i++) { reqs[i] = request_borrow(); ck_assert_msg(reqs[i] != NULL, "expected to borrow a request"); } ck_assert_msg(request_borrow() == NULL, "expected request pool to be depleted"); for (i = 0; i < POOL_SIZE; i++) { request_return(&reqs[i]); ck_assert_msg(reqs[i] == NULL, "expected request to be nulled after return"); } request_teardown(); #undef POOL_SIZE } END_TEST START_TEST(test_rsp_pool_basic) { #define POOL_SIZE 10 int i; struct response *rsps[POOL_SIZE]; response_options_st options = { .response_ntoken = {.type = OPTION_TYPE_UINT, .val.vuint = RSP_NTOKEN}, .response_poolsize = {.type = OPTION_TYPE_UINT, .val.vuint = POOL_SIZE}}; response_setup(&options, NULL); for (i = 0; i < POOL_SIZE; i++) { rsps[i] = response_borrow(); ck_assert_msg(rsps[i] != NULL, "expected to borrow a response"); } ck_assert_msg(response_borrow() == NULL, "expected response pool to be depleted"); for (i = 0; i < POOL_SIZE; i++) { response_return(&rsps[i]); ck_assert_msg(rsps[i] == NULL, "expected response to be nulled after return"); } response_teardown(); #undef POOL_SIZE } END_TEST /* * test suite */ static Suite * redis_suite(void) { Suite *s = suite_create(SUITE_NAME); /* token */ TCase *tc_token = tcase_create("token"); suite_add_tcase(s, tc_token); tcase_add_test(tc_token, test_simple_string); tcase_add_test(tc_token, test_error); tcase_add_test(tc_token, test_integer); tcase_add_test(tc_token, test_bulk_string); tcase_add_test(tc_token, test_array); tcase_add_test(tc_token, test_nil_bulk); tcase_add_test(tc_token, test_unfin_token); /* basic requests */ TCase *tc_request = tcase_create("request"); suite_add_tcase(s, tc_request); tcase_add_test(tc_request, test_quit); tcase_add_test(tc_request, test_ping); tcase_add_test(tc_request, test_unfin_req); /* basic responses */ TCase *tc_response = tcase_create("response"); suite_add_tcase(s, tc_response); tcase_add_test(tc_response, test_ok); tcase_add_test(tc_response, test_array_reply); /* edge cases */ TCase *tc_edge = tcase_create("edge cases"); suite_add_tcase(s, tc_edge); tcase_add_test(tc_edge, test_empty_buf); /* req/rsp objects, pooling */ TCase *tc_pool = tcase_create("request/response pool"); suite_add_tcase(s, tc_pool); tcase_add_test(tc_pool, test_req_pool_basic); tcase_add_test(tc_pool, test_rsp_pool_basic); return s; } /* TODO(yao): move main to a different file, keep most test files main-less */ int main(void) { int nfail; /* setup */ test_setup(); Suite *suite = redis_suite(); SRunner *srunner = srunner_create(suite); srunner_set_log(srunner, DEBUG_LOG); srunner_run_all(srunner, CK_ENV); /* set CK_VEBOSITY in ENV to customize */ nfail = srunner_ntests_failed(srunner); srunner_free(srunner); /* teardown */ test_teardown(); return (nfail == 0) ? EXIT_SUCCESS : EXIT_FAILURE; }
void prim_array_filter_prop(PRIM_PROTOTYPE) { char pattern[BUFFER_LEN]; char tname[BUFFER_LEN]; struct inst *in; struct inst temp1; stk_array *arr; stk_array *nu; char* prop; int len; CHECKOP(3); oper3 = POP(); /* str pattern */ oper2 = POP(); /* str propname */ oper1 = POP(); /* refarr Array */ if (oper1->type != PROG_ARRAY) abort_interp("Argument not an array. (1)"); if (!array_is_homogenous(oper1->data.array, PROG_OBJECT)) abort_interp("Argument not an array of dbrefs. (1)"); if (oper2->type != PROG_STRING || !oper2->data.string) abort_interp("Argument not a non-null string. (2)"); if (oper3->type != PROG_STRING) abort_interp("Argument not a string pattern. (3)"); len = oper2->data.string ? oper2->data.string->length : 0; strcpyn(tname, sizeof(tname), DoNullInd(oper2->data.string)); while (len-- > 0 && tname[len] == PROPDIR_DELIMITER) { tname[len] = '\0'; } nu = new_array_packed(0); arr = oper1->data.array; prop = tname; strcpyn(pattern, sizeof(pattern), DoNullInd(oper3->data.string)); if (array_first(arr, &temp1)) { do { in = array_getitem(arr, &temp1); if (valid_object(in)) { ref = in->data.objref; CHECKREMOTE(ref); if (prop_read_perms(ProgUID, ref, prop, mlev)) { PropPtr pptr = get_property(ref, prop); if (pptr) { switch(PropType(pptr)) { case PROP_STRTYP: strncpy(buf, PropDataStr(pptr), BUFFER_LEN); break; case PROP_LOKTYP: if (PropFlags(pptr) & PROP_ISUNLOADED) { strncpy(buf, "*UNLOCKED*", BUFFER_LEN); } else { strncpy(buf, unparse_boolexp(ProgUID, PropDataLok(pptr), 0), BUFFER_LEN); } break; case PROP_REFTYP: snprintf(buf, BUFFER_LEN, "#%i", PropDataRef(pptr)); break; case PROP_INTTYP: snprintf(buf, BUFFER_LEN, "%i", PropDataVal(pptr)); break; case PROP_FLTTYP: snprintf(buf, BUFFER_LEN, "%g", PropDataFVal(pptr)); break; default: strncpy(buf, "", BUFFER_LEN); break; } } else strncpy(buf, "", BUFFER_LEN); if (equalstr(pattern, buf)) { array_appenditem(&nu, in); } } } } while (array_next(arr, &temp1)); } CLEAR(oper3); CLEAR(oper2); CLEAR(oper1); PushArrayRaw(nu); }
int array_insertrange(stk_array **harr, array_iter *start, stk_array *inarr) { stk_array *arr; array_data *itm; array_iter idx; array_iter didx; if (!harr || !*harr) { return -1; } arr = *harr; if (!inarr || !inarr->items) { return arr->items; } switch (arr->type) { case ARRAY_PACKED:{ if (!start) { return -1; } if (start->type != PROG_INTEGER) { return -1; } if (start->data.number < 0 || start->data.number > arr->items) { return -1; } if (arr->links > 1 && !arr->pinned) { arr->links--; arr = *harr = array_decouple(arr); } arr->data.packed = (array_data *) realloc(arr->data.packed, sizeof(array_data) * (arr->items + inarr->items)); copyinst(start, &idx); copyinst(start, &didx); idx.data.number = arr->items - 1; didx.data.number = arr->items + inarr->items - 1; while (idx.data.number >= start->data.number) { itm = array_getitem(arr, &idx); copyinst(itm, &arr->data.packed[didx.data.number]); CLEAR(itm); idx.data.number--; didx.data.number--; } if (array_first(inarr, &idx)) { do { itm = array_getitem(inarr, &idx); copyinst(itm, &arr->data.packed[start->data.number]); start->data.number++; } while (array_next(inarr, &idx)); } arr->items += inarr->items; return arr->items; break; } case ARRAY_DICTIONARY:{ if (arr->links > 1 && !arr->pinned) { arr->links--; arr = *harr = array_decouple(arr); } if (array_first(inarr, &idx)) { do { array_setitem(&arr, &idx, array_getitem(inarr, &idx)); } while (array_next(inarr, &idx)); } return arr->items; break; } default: break; } return -1; }
void prim_array_regmatchval(PRIM_PROTOTYPE) { struct inst *in; stk_array *arr; stk_array *nw; muf_re* re; char* text; int flags; int matchcnt = 0; const char* errstr = NULL; CHECKOP(3); oper3 = POP(); /* int pcreflags */ oper2 = POP(); /* str pattern */ oper1 = POP(); /* arr Array */ if (oper1->type != PROG_ARRAY) abort_interp("Argument not an array. (1)"); if (oper2->type != PROG_STRING) abort_interp("Argument not a string pattern. (2)"); if (oper3->type != PROG_INTEGER) abort_interp("Non-integer argument (3)"); flags = PCRE_NO_AUTO_CAPTURE; if (oper3->data.number & MUF_RE_ICASE) flags |= PCRE_CASELESS; if (oper3->data.number & MUF_RE_EXTENDED) flags |= PCRE_EXTENDED; re = regmatch_re_get(oper2->data.string, flags, &errstr); if (errstr) abort_interp(errstr) nw = new_array_dictionary(); arr = oper1->data.array; if (re && !re->extra && array_count(arr) > 2) { /* This pattern is getting used 3 or more times, let's study it. A null * return is okay, that just means there's nothing to optimize. */ re->extra = pcre_study(re->re, 0, &errstr); if (errstr) abort_interp(errstr); } if (array_first(arr, &temp1)) { do { in = array_getitem(arr, &temp1); if (in->type == PROG_STRING) { text = (char *)DoNullInd(in->data.string); if ((matchcnt = regmatch_exec(re, text)) < 0) { if (matchcnt != PCRE_ERROR_NOMATCH) abort_interp(muf_re_error(matchcnt)); } else { array_setitem(&nw, &temp1, in); } } else if (in->type == PROG_OBJECT) { text = (char *) NAME(in->data.objref); if ((matchcnt = regmatch_exec(re, text)) < 0) { if (matchcnt != PCRE_ERROR_NOMATCH) abort_interp(muf_re_error(matchcnt)); } else { array_setitem(&nw, &temp1, in); } } } while (array_next(arr, &temp1)); } CLEAR(oper3); CLEAR(oper2); CLEAR(oper1); PushArrayRaw(nw); }
void prim_array_regfilter_prop(PRIM_PROTOTYPE) { char buf[BUFFER_LEN]; struct inst *in; stk_array *arr; stk_array *nu; char* prop; const char* ptr; muf_re* re; int flags; int matchcnt = 0; const char* errstr = NULL; CHECKOP(4); oper4 = POP(); /* int pcreflags */ oper3 = POP(); /* str pattern */ oper2 = POP(); /* str propname */ oper1 = POP(); /* refarr Array */ if (oper1->type != PROG_ARRAY) abort_interp("Argument not an array. (1)"); if (!array_is_homogenous(oper1->data.array, PROG_OBJECT)) abort_interp("Argument not an array of dbrefs. (1)"); if (oper2->type != PROG_STRING || !oper2->data.string) abort_interp("Argument not a non-null string. (2)"); if (oper3->type != PROG_STRING) abort_interp("Argument not a string pattern. (3)"); if (oper4->type != PROG_INTEGER) abort_interp("Non-integer argument (4)"); ptr = oper2->data.string->data; while ((ptr = index(ptr, PROPDIR_DELIMITER))) if (!(*(++ptr))) abort_interp("Cannot access a propdir directly."); nu = new_array_packed(0); arr = oper1->data.array; flags = PCRE_NO_AUTO_CAPTURE; if (oper4->data.number & MUF_RE_ICASE) flags |= PCRE_CASELESS; if (oper4->data.number & MUF_RE_EXTENDED) flags |= PCRE_EXTENDED; re = regmatch_re_get(oper3->data.string, flags, &errstr); if (errstr) abort_interp(errstr) if (re && !re->extra && array_count(arr) > 2) { /* This pattern is getting used 3 or more times, let's study it. A null * return is okay, that just means there's nothing to optimize. */ re->extra = pcre_study(re->re, 0, &errstr); if (errstr) abort_interp(errstr); } prop = (char *) DoNullInd(oper2->data.string); if (array_first(arr, &temp1)) { do { in = array_getitem(arr, &temp1); if (valid_object(in)) { ref = in->data.objref; CHECKREMOTE(ref); if (prop_read_perms(ProgUID, ref, prop, mlev)) { ptr = get_property_class(ref, prop); if (ptr) strcpy(buf, ptr); else strcpy(buf, ""); if ((matchcnt = regmatch_exec(re, buf)) < 0) { if (matchcnt != PCRE_ERROR_NOMATCH) abort_interp(muf_re_error(matchcnt)); } else { array_appenditem(&nu, in); } } } } while (array_next(arr, &temp1)); } CLEAR(oper4); CLEAR(oper3); CLEAR(oper2); CLEAR(oper1); PushArrayRaw(nu); }
void prim_parsepropex(PRIM_PROTOTYPE) { struct inst* oper1 = NULL; /* prevents reentrancy issues! */ struct inst* oper2 = NULL; /* prevents reentrancy issues! */ struct inst* oper3 = NULL; /* prevents reentrancy issues! */ struct inst* oper4 = NULL; /* prevents reentrancy issues! */ stk_array* vars; const char* mpi; char* str = 0; array_iter idx; extern int varc; /* from msgparse.c */ int mvarcnt = 0; char* buffers = NULL; int novars; int hashow = 0; int i; int len; char tname[BUFFER_LEN]; char buf[BUFFER_LEN]; CHECKOP(4); oper4 = POP(); /* int:Private */ oper3 = POP(); /* dict:Vars */ oper2 = POP(); /* str:Prop */ oper1 = POP(); /* ref:Object */ if (mlev < 3) abort_interp("Mucker level 3 or greater required."); if (oper1->type != PROG_OBJECT) abort_interp("Non-object argument. (1)"); if (oper2->type != PROG_STRING) abort_interp("Non-string argument. (2)"); if (oper3->type != PROG_ARRAY) abort_interp("Non-array argument. (3)"); if (oper3->data.array && (oper3->data.array->type != ARRAY_DICTIONARY)) abort_interp("Dictionary array expected. (3)"); if (oper4->type != PROG_INTEGER) abort_interp("Non-integer argument. (4)"); if (!valid_object(oper1)) abort_interp("Invalid object. (1)"); if (!oper2->data.string) abort_interp("Empty string argument. (2)"); if ((oper4->data.number != 0) && (oper4->data.number != 1)) abort_interp("Integer of 0 or 1 expected. (4)"); CHECKREMOTE(oper1->data.objref); if (!prop_read_perms(ProgUID, oper1->data.objref, oper2->data.string->data, mlev)) abort_interp("Permission denied."); len = oper2->data.string->length; strcpyn(tname, sizeof(tname), oper2->data.string->data); while (len-- > 0 && tname[len] == PROPDIR_DELIMITER) { tname[len] = '\0'; } mpi = get_property_class(oper1->data.objref, tname); vars = oper3->data.array; novars = array_count(vars); if (check_mvar_overflow(novars)) abort_interp("Out of MPI variables. (3)"); if (array_first(vars, &idx)) { do { array_data* val = array_getitem(vars, &idx); if (idx.type != PROG_STRING) { CLEAR(&idx); abort_interp("Only string keys supported. (3)"); } if (idx.data.string == NULL) { CLEAR(&idx); abort_interp("Empty string keys not supported. (3)"); } if (strlen(idx.data.string->data) > MAX_MFUN_NAME_LEN) { CLEAR(&idx); abort_interp("Key too long to be an MPI variable. (3)"); } switch(val->type) { case PROG_INTEGER: case PROG_FLOAT: case PROG_OBJECT: case PROG_STRING: case PROG_LOCK: break; default: CLEAR(&idx); abort_interp("Only integer, float, dbref, string and lock values supported. (3)"); break; } if (string_compare(idx.data.string->data, "how") == 0) hashow = 1; } while(array_next(vars, &idx)); } if (mpi && *mpi) { if (novars > 0) { mvarcnt = varc; if ((buffers = (char*)malloc(novars * BUFFER_LEN)) == NULL) abort_interp("Out of memory."); if (array_first(vars, &idx)) { i = 0; do { char* var_buf = buffers + (i++ * BUFFER_LEN); array_data* val; val = array_getitem(vars, &idx); switch(val->type) { case PROG_INTEGER: snprintf(var_buf, BUFFER_LEN, "%i", val->data.number); break; case PROG_FLOAT: snprintf(var_buf, BUFFER_LEN, "%g", val->data.fnumber); break; case PROG_OBJECT: snprintf(var_buf, BUFFER_LEN, "#%i", val->data.objref); break; case PROG_STRING: strncpy(var_buf, DoNullInd(val->data.string), BUFFER_LEN); break; case PROG_LOCK: strncpy(var_buf, unparse_boolexp(ProgUID, val->data.lock, 1), BUFFER_LEN); break; default: var_buf[0] = '\0'; break; } var_buf[BUFFER_LEN - 1] = '\0'; new_mvar(idx.data.string->data, var_buf); } while(array_next(vars, &idx)); } } result = 0; if (oper4->data.number) result |= MPI_ISPRIVATE; if (Prop_Blessed(oper1->data.objref, oper2->data.string->data)) result |= MPI_ISBLESSED; if (hashow) result |= MPI_NOHOW; str = do_parse_mesg(fr->descr, player, oper1->data.objref, mpi, "(parsepropex)", buf, sizeof(buf), result); if (novars > 0) { if (array_first(vars, &idx)) { i = 0; do { char* var_buf = buffers + (i++ * BUFFER_LEN); struct inst temp; temp.type = PROG_STRING; temp.data.string = alloc_prog_string(var_buf); array_setitem(&vars, &idx, &temp); CLEAR(&temp); } while(array_next(vars, &idx)); } free(buffers); varc = mvarcnt; } } oper3->data.array = NULL; CLEAR(oper1); CLEAR(oper2); CLEAR(oper3); CLEAR(oper4); PushArrayRaw(vars); PushString(str); }