From f973eeb4911de09258e84cb2248dc0f9392824b4 Mon Sep 17 00:00:00 2001 From: Yegappan Lakshmanan Date: Wed, 22 Dec 2021 18:19:26 +0000 Subject: patch 8.2.3871: list.c contains code for dict and blob Problem: List.c contains code for dict and blob. Solution: Refactor to put code where it belongs. (Yegappan Lakshmanan, closes #9386) --- src/blob.c | 324 ++++++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 276 insertions(+), 48 deletions(-) (limited to 'src/blob.c') diff --git a/src/blob.c b/src/blob.c index 5658370527..1387a8e653 100644 --- a/src/blob.c +++ b/src/blob.c @@ -410,78 +410,306 @@ blob_set_range(blob_T *dest, long n1, long n2, typval_T *src) } /* - * "remove({blob})" function + * "add(blob, item)" function + */ + void +blob_add(typval_T *argvars, typval_T *rettv) +{ + blob_T *b = argvars[0].vval.v_blob; + int error = FALSE; + varnumber_T n; + + if (b == NULL) + { + if (in_vim9script()) + emsg(_(e_cannot_add_to_null_blob)); + return; + } + + if (value_check_lock(b->bv_lock, (char_u *)N_("add() argument"), TRUE)) + return; + + n = tv_get_number_chk(&argvars[1], &error); + if (error) + return; + + ga_append(&b->bv_ga, (int)n); + copy_tv(&argvars[0], rettv); +} + +/* + * "remove({blob}, {idx} [, {end}])" function */ void blob_remove(typval_T *argvars, typval_T *rettv, char_u *arg_errmsg) { blob_T *b = argvars[0].vval.v_blob; + blob_T *newblob; int error = FALSE; long idx; long end; + int len; + char_u *p; if (b != NULL && value_check_lock(b->bv_lock, arg_errmsg, TRUE)) return; idx = (long)tv_get_number_chk(&argvars[1], &error); - if (!error) + if (error) + return; + + len = blob_len(b); + + if (idx < 0) + // count from the end + idx = len + idx; + if (idx < 0 || idx >= len) + { + semsg(_(e_blobidx), idx); + return; + } + if (argvars[2].v_type == VAR_UNKNOWN) { - int len = blob_len(b); - char_u *p; + // Remove one item, return its value. + p = (char_u *)b->bv_ga.ga_data; + rettv->vval.v_number = (varnumber_T) *(p + idx); + mch_memmove(p + idx, p + idx + 1, (size_t)len - idx - 1); + --b->bv_ga.ga_len; + return; + } - if (idx < 0) - // count from the end - idx = len + idx; - if (idx < 0 || idx >= len) - { - semsg(_(e_blobidx), idx); + // Remove range of items, return blob with values. + end = (long)tv_get_number_chk(&argvars[2], &error); + if (error) + return; + if (end < 0) + // count from the end + end = len + end; + if (end >= len || idx > end) + { + semsg(_(e_blobidx), end); + return; + } + newblob = blob_alloc(); + if (newblob == NULL) + return; + newblob->bv_ga.ga_len = end - idx + 1; + if (ga_grow(&newblob->bv_ga, end - idx + 1) == FAIL) + { + vim_free(newblob); + return; + } + p = (char_u *)b->bv_ga.ga_data; + mch_memmove((char_u *)newblob->bv_ga.ga_data, p + idx, + (size_t)(end - idx + 1)); + ++newblob->bv_refcount; + rettv->v_type = VAR_BLOB; + rettv->vval.v_blob = newblob; + + if (len - end - 1 > 0) + mch_memmove(p + idx, p + end + 1, (size_t)(len - end - 1)); + b->bv_ga.ga_len -= end - idx + 1; +} + +/* + * Implementation of map() and filter() for a Blob. Apply "expr" to every + * number in Blob "blob_arg" and return the result in "rettv". + */ + void +blob_filter_map( + blob_T *blob_arg, + filtermap_T filtermap, + typval_T *expr, + typval_T *rettv) +{ + blob_T *b; + int i; + typval_T tv; + varnumber_T val; + blob_T *b_ret; + int idx = 0; + int rem; + + if (filtermap == FILTERMAP_MAPNEW) + { + rettv->v_type = VAR_BLOB; + rettv->vval.v_blob = NULL; + } + if ((b = blob_arg) == NULL) + return; + + b_ret = b; + if (filtermap == FILTERMAP_MAPNEW) + { + if (blob_copy(b, rettv) == FAIL) return; + b_ret = rettv->vval.v_blob; + } + + // set_vim_var_nr() doesn't set the type + set_vim_var_type(VV_KEY, VAR_NUMBER); + + for (i = 0; i < b->bv_ga.ga_len; i++) + { + typval_T newtv; + + tv.v_type = VAR_NUMBER; + val = blob_get(b, i); + tv.vval.v_number = val; + set_vim_var_nr(VV_KEY, idx); + if (filter_map_one(&tv, expr, filtermap, &newtv, &rem) == FAIL + || did_emsg) + break; + if (newtv.v_type != VAR_NUMBER && newtv.v_type != VAR_BOOL) + { + clear_tv(&newtv); + emsg(_(e_invalblob)); + break; } - if (argvars[2].v_type == VAR_UNKNOWN) + if (filtermap != FILTERMAP_FILTER) { - // Remove one item, return its value. - p = (char_u *)b->bv_ga.ga_data; - rettv->vval.v_number = (varnumber_T) *(p + idx); - mch_memmove(p + idx, p + idx + 1, (size_t)len - idx - 1); + if (newtv.vval.v_number != val) + blob_set(b_ret, i, newtv.vval.v_number); + } + else if (rem) + { + char_u *p = (char_u *)blob_arg->bv_ga.ga_data; + + mch_memmove(p + i, p + i + 1, + (size_t)b->bv_ga.ga_len - i - 1); --b->bv_ga.ga_len; + --i; } - else + ++idx; + } +} + +/* + * "insert(blob, {item} [, {idx}])" function + */ + void +blob_insert_func(typval_T *argvars, typval_T *rettv) +{ + blob_T *b = argvars[0].vval.v_blob; + long before = 0; + int error = FALSE; + int val, len; + char_u *p; + + if (b == NULL) + { + if (in_vim9script()) + emsg(_(e_cannot_add_to_null_blob)); + return; + } + + if (value_check_lock(b->bv_lock, (char_u *)N_("insert() argument"), TRUE)) + return; + + len = blob_len(b); + if (argvars[2].v_type != VAR_UNKNOWN) + { + before = (long)tv_get_number_chk(&argvars[2], &error); + if (error) + return; // type error; errmsg already given + if (before < 0 || before > len) { - blob_T *blob; - - // Remove range of items, return blob with values. - end = (long)tv_get_number_chk(&argvars[2], &error); - if (error) - return; - if (end < 0) - // count from the end - end = len + end; - if (end >= len || idx > end) - { - semsg(_(e_blobidx), end); - return; - } - blob = blob_alloc(); - if (blob == NULL) - return; - blob->bv_ga.ga_len = end - idx + 1; - if (ga_grow(&blob->bv_ga, end - idx + 1) == FAIL) - { - vim_free(blob); - return; - } - p = (char_u *)b->bv_ga.ga_data; - mch_memmove((char_u *)blob->bv_ga.ga_data, p + idx, - (size_t)(end - idx + 1)); - ++blob->bv_refcount; - rettv->v_type = VAR_BLOB; - rettv->vval.v_blob = blob; + semsg(_(e_invarg2), tv_get_string(&argvars[2])); + return; + } + } + val = tv_get_number_chk(&argvars[1], &error); + if (error) + return; + if (val < 0 || val > 255) + { + semsg(_(e_invarg2), tv_get_string(&argvars[1])); + return; + } + + if (ga_grow(&b->bv_ga, 1) == FAIL) + return; + p = (char_u *)b->bv_ga.ga_data; + mch_memmove(p + before + 1, p + before, (size_t)len - before); + *(p + before) = val; + ++b->bv_ga.ga_len; + + copy_tv(&argvars[0], rettv); +} + +/* + * reduce() Blob argvars[0] using the function 'funcname' with arguments in + * 'funcexe' starting with the initial value argvars[2] and return the result + * in 'rettv'. + */ + void +blob_reduce( + typval_T *argvars, + char_u *func_name, + funcexe_T *funcexe, + typval_T *rettv) +{ + blob_T *b = argvars[0].vval.v_blob; + int called_emsg_start = called_emsg; + int r; + typval_T initial; + typval_T argv[3]; + int i; - if (len - end - 1 > 0) - mch_memmove(p + idx, p + end + 1, (size_t)(len - end - 1)); - b->bv_ga.ga_len -= end - idx + 1; + if (argvars[2].v_type == VAR_UNKNOWN) + { + if (b == NULL || b->bv_ga.ga_len == 0) + { + semsg(_(e_reduceempty), "Blob"); + return; } + initial.v_type = VAR_NUMBER; + initial.vval.v_number = blob_get(b, 0); + i = 1; + } + else if (argvars[2].v_type != VAR_NUMBER) + { + emsg(_(e_number_expected)); + return; + } + else + { + initial = argvars[2]; + i = 0; + } + + copy_tv(&initial, rettv); + if (b == NULL) + return; + + for ( ; i < b->bv_ga.ga_len; i++) + { + argv[0] = *rettv; + argv[1].v_type = VAR_NUMBER; + argv[1].vval.v_number = blob_get(b, i); + r = call_func(func_name, -1, rettv, 2, argv, funcexe); + clear_tv(&argv[0]); + if (r == FAIL || called_emsg != called_emsg_start) + return; + } +} + +/* + * "reverse({blob})" function + */ + void +blob_reverse(blob_T *b, typval_T *rettv) +{ + int i, len = blob_len(b); + + for (i = 0; i < len / 2; i++) + { + int tmp = blob_get(b, i); + + blob_set(b, i, blob_get(b, len - i - 1)); + blob_set(b, len - i - 1, tmp); } + rettv_blob_set(rettv, b); } /* -- cgit v1.2.3