diff src/blob.c @ 26684:2126feddeda6 v8.2.3871

patch 8.2.3871: list.c contains code for dict and blob Commit: https://github.com/vim/vim/commit/f973eeb4911de09258e84cb2248dc0f9392824b4 Author: Yegappan Lakshmanan <yegappan@yahoo.com> Date: Wed Dec 22 18:19:26 2021 +0000 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)
author Bram Moolenaar <Bram@vim.org>
date Wed, 22 Dec 2021 19:30:04 +0100
parents a3f38923c037
children 6ee19c6ae8a2
line wrap: on
line diff
--- a/src/blob.c
+++ b/src/blob.c
@@ -410,81 +410,309 @@ blob_set_range(blob_T *dest, long n1, lo
 }
 
 /*
- * "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)
+    {
+	// 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;
+    }
+
+    // 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)
     {
-	int	len = blob_len(b);
-	char_u  *p;
+	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 (idx < 0)
-	    // count from the end
-	    idx = len + idx;
-	if (idx < 0 || idx >= len)
+    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 (filtermap != FILTERMAP_FILTER)
+	{
+	    if (newtv.vval.v_number != val)
+		blob_set(b_ret, i, newtv.vval.v_number);
+	}
+	else if (rem)
 	{
-	    semsg(_(e_blobidx), idx);
+	    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;
+	}
+	++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)
+	{
+	    semsg(_(e_invarg2), tv_get_string(&argvars[2]));
 	    return;
 	}
-	if (argvars[2].v_type == VAR_UNKNOWN)
-	{
-	    // 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;
-	}
-	else
-	{
-	    blob_T  *blob;
+    }
+    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;
 
-	    // 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;
+    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;
 
-	    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;
-	}
+    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);
+}
+
+/*
  * blob2list() function
  */
     void