blob: a4e99818c396299664e1997516cfe192340412dd [file] [log] [blame]
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001/* vi:set ts=8 sts=4 sw=4 noet:
2 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9
10/*
11 * blob.c: Blob support by Yasuhiro Matsumoto
12 */
13
14#include "vim.h"
15
16#if defined(FEAT_EVAL) || defined(PROTO)
17
18/*
19 * Allocate an empty blob.
20 * Caller should take care of the reference count.
21 */
22 blob_T *
23blob_alloc(void)
24{
Yegappan Lakshmanan72bb47e2022-04-03 11:22:38 +010025 blob_T *blob = ALLOC_CLEAR_ONE_ID(blob_T, aid_blob_alloc);
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010026
27 if (blob != NULL)
28 ga_init2(&blob->bv_ga, 1, 100);
29 return blob;
30}
31
32/*
33 * Allocate an empty blob for a return value, with reference count set.
34 * Returns OK or FAIL.
35 */
36 int
37rettv_blob_alloc(typval_T *rettv)
38{
39 blob_T *b = blob_alloc();
40
41 if (b == NULL)
42 return FAIL;
43
44 rettv_blob_set(rettv, b);
45 return OK;
46}
47
48/*
49 * Set a blob as the return value.
50 */
51 void
52rettv_blob_set(typval_T *rettv, blob_T *b)
53{
54 rettv->v_type = VAR_BLOB;
55 rettv->vval.v_blob = b;
56 if (b != NULL)
57 ++b->bv_refcount;
58}
59
Bram Moolenaardd29ea12019-01-23 21:56:21 +010060 int
Bram Moolenaar8a7d6542020-01-26 15:56:19 +010061blob_copy(blob_T *from, typval_T *to)
Bram Moolenaardd29ea12019-01-23 21:56:21 +010062{
Yegappan Lakshmanan368aa692022-09-27 11:46:48 +010063 int len;
Bram Moolenaardd29ea12019-01-23 21:56:21 +010064
65 to->v_type = VAR_BLOB;
Bram Moolenaarb7b9efb2019-07-12 20:17:03 +020066 to->v_lock = 0;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +010067 if (from == NULL)
Bram Moolenaardd29ea12019-01-23 21:56:21 +010068 {
Yegappan Lakshmanan368aa692022-09-27 11:46:48 +010069 to->vval.v_blob = NULL;
70 return OK;
Bram Moolenaardd29ea12019-01-23 21:56:21 +010071 }
Yegappan Lakshmanan368aa692022-09-27 11:46:48 +010072
73 if (rettv_blob_alloc(to) == FAIL)
74 return FAIL;
75
76 len = from->bv_ga.ga_len;
77 if (len > 0)
78 {
79 to->vval.v_blob->bv_ga.ga_data =
80 vim_memsave(from->bv_ga.ga_data, len);
81 if (to->vval.v_blob->bv_ga.ga_data == NULL)
82 len = 0;
83 }
84 to->vval.v_blob->bv_ga.ga_len = len;
85 to->vval.v_blob->bv_ga.ga_maxlen = len;
86
87 return OK;
Bram Moolenaardd29ea12019-01-23 21:56:21 +010088}
89
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010090 void
91blob_free(blob_T *b)
92{
93 ga_clear(&b->bv_ga);
94 vim_free(b);
95}
96
97/*
98 * Unreference a blob: decrement the reference count and free it when it
99 * becomes zero.
100 */
101 void
102blob_unref(blob_T *b)
103{
104 if (b != NULL && --b->bv_refcount <= 0)
105 blob_free(b);
106}
107
108/*
109 * Get the length of data.
110 */
111 long
112blob_len(blob_T *b)
113{
114 if (b == NULL)
115 return 0L;
116 return b->bv_ga.ga_len;
117}
118
119/*
120 * Get byte "idx" in blob "b".
121 * Caller must check that "idx" is valid.
122 */
Bram Moolenaara5be9b62019-01-24 12:31:44 +0100123 int
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +0100124blob_get(blob_T *b, int idx)
125{
126 return ((char_u*)b->bv_ga.ga_data)[idx];
127}
128
129/*
Bram Moolenaar51e93322021-04-17 20:44:56 +0200130 * Store one byte "byte" in blob "blob" at "idx".
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +0100131 * Caller must make sure that "idx" is valid.
132 */
133 void
Bram Moolenaar51e93322021-04-17 20:44:56 +0200134blob_set(blob_T *blob, int idx, int byte)
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +0100135{
Bram Moolenaar51e93322021-04-17 20:44:56 +0200136 ((char_u*)blob->bv_ga.ga_data)[idx] = byte;
137}
138
139/*
140 * Store one byte "byte" in blob "blob" at "idx".
141 * Append one byte if needed.
142 */
143 void
144blob_set_append(blob_T *blob, int idx, int byte)
145{
146 garray_T *gap = &blob->bv_ga;
147
148 // Allow for appending a byte. Setting a byte beyond
149 // the end is an error otherwise.
150 if (idx < gap->ga_len
151 || (idx == gap->ga_len && ga_grow(gap, 1) == OK))
152 {
153 blob_set(blob, idx, byte);
154 if (idx == gap->ga_len)
155 ++gap->ga_len;
156 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +0100157}
158
159/*
160 * Return TRUE when two blobs have exactly the same values.
161 */
162 int
163blob_equal(
164 blob_T *b1,
165 blob_T *b2)
166{
Bram Moolenaarc0f5a782019-01-13 15:16:13 +0100167 int i;
168 int len1 = blob_len(b1);
169 int len2 = blob_len(b2);
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +0100170
Bram Moolenaarc0f5a782019-01-13 15:16:13 +0100171 // empty and NULL are considered the same
172 if (len1 == 0 && len2 == 0)
173 return TRUE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +0100174 if (b1 == b2)
175 return TRUE;
Bram Moolenaarc0f5a782019-01-13 15:16:13 +0100176 if (len1 != len2)
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +0100177 return FALSE;
178
179 for (i = 0; i < b1->bv_ga.ga_len; i++)
180 if (blob_get(b1, i) != blob_get(b2, i)) return FALSE;
181 return TRUE;
182}
183
184/*
185 * Read "blob" from file "fd".
186 * Return OK or FAIL.
187 */
188 int
189read_blob(FILE *fd, blob_T *blob)
190{
191 struct stat st;
192
193 if (fstat(fileno(fd), &st) < 0)
194 return FAIL;
195 if (ga_grow(&blob->bv_ga, st.st_size) == FAIL)
196 return FAIL;
197 blob->bv_ga.ga_len = st.st_size;
198 if (fread(blob->bv_ga.ga_data, 1, blob->bv_ga.ga_len, fd)
199 < (size_t)blob->bv_ga.ga_len)
200 return FAIL;
201 return OK;
202}
203
204/*
205 * Write "blob" to file "fd".
206 * Return OK or FAIL.
207 */
208 int
209write_blob(FILE *fd, blob_T *blob)
210{
211 if (fwrite(blob->bv_ga.ga_data, 1, blob->bv_ga.ga_len, fd)
212 < (size_t)blob->bv_ga.ga_len)
213 {
Bram Moolenaar40bcec12021-12-05 22:19:27 +0000214 emsg(_(e_error_while_writing));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +0100215 return FAIL;
216 }
217 return OK;
218}
219
Bram Moolenaar8c8b8bb2019-01-13 17:48:04 +0100220/*
Bram Moolenaar4131fd52019-01-17 16:32:53 +0100221 * Convert a blob to a readable form: "0z00112233.44556677.8899"
Bram Moolenaar8c8b8bb2019-01-13 17:48:04 +0100222 */
223 char_u *
224blob2string(blob_T *blob, char_u **tofree, char_u *numbuf)
225{
226 int i;
227 garray_T ga;
228
229 if (blob == NULL)
230 {
231 *tofree = NULL;
Bram Moolenaar4131fd52019-01-17 16:32:53 +0100232 return (char_u *)"0z";
Bram Moolenaar8c8b8bb2019-01-13 17:48:04 +0100233 }
234
235 // Store bytes in the growarray.
236 ga_init2(&ga, 1, 4000);
Bram Moolenaar4131fd52019-01-17 16:32:53 +0100237 ga_concat(&ga, (char_u *)"0z");
Bram Moolenaar8c8b8bb2019-01-13 17:48:04 +0100238 for (i = 0; i < blob_len(blob); i++)
239 {
Bram Moolenaar4131fd52019-01-17 16:32:53 +0100240 if (i > 0 && (i & 3) == 0)
241 ga_concat(&ga, (char_u *)".");
=?UTF-8?q?Dundar=20G=C3=B6c?=420fabc2022-01-28 15:28:04 +0000242 vim_snprintf((char *)numbuf, NUMBUFLEN, "%02X", blob_get(blob, i));
Bram Moolenaar8c8b8bb2019-01-13 17:48:04 +0100243 ga_concat(&ga, numbuf);
244 }
Yegappan Lakshmananbc404bf2021-12-19 19:19:31 +0000245 ga_append(&ga, NUL); // append a NUL at the end
Bram Moolenaar8c8b8bb2019-01-13 17:48:04 +0100246 *tofree = ga.ga_data;
247 return *tofree;
248}
249
250/*
251 * Convert a string variable, in the format of blob2string(), to a blob.
252 * Return NULL when conversion failed.
253 */
254 blob_T *
255string2blob(char_u *str)
256{
257 blob_T *blob = blob_alloc();
258 char_u *s = str;
259
Bram Moolenaare142a942019-03-19 23:03:27 +0100260 if (blob == NULL)
261 return NULL;
Bram Moolenaar4131fd52019-01-17 16:32:53 +0100262 if (s[0] != '0' || (s[1] != 'z' && s[1] != 'Z'))
Bram Moolenaar8c8b8bb2019-01-13 17:48:04 +0100263 goto failed;
Bram Moolenaar4131fd52019-01-17 16:32:53 +0100264 s += 2;
265 while (vim_isxdigit(*s))
Bram Moolenaar8c8b8bb2019-01-13 17:48:04 +0100266 {
Bram Moolenaar4131fd52019-01-17 16:32:53 +0100267 if (!vim_isxdigit(s[1]))
Bram Moolenaar8c8b8bb2019-01-13 17:48:04 +0100268 goto failed;
Bram Moolenaar4131fd52019-01-17 16:32:53 +0100269 ga_append(&blob->bv_ga, (hex2nr(s[0]) << 4) + hex2nr(s[1]));
270 s += 2;
271 if (*s == '.' && vim_isxdigit(s[1]))
272 ++s;
Bram Moolenaar8c8b8bb2019-01-13 17:48:04 +0100273 }
Bram Moolenaar4131fd52019-01-17 16:32:53 +0100274 if (*skipwhite(s) != NUL)
275 goto failed; // text after final digit
Bram Moolenaar8c8b8bb2019-01-13 17:48:04 +0100276
277 ++blob->bv_refcount;
278 return blob;
279
280failed:
281 blob_free(blob);
282 return NULL;
283}
284
Yegappan Lakshmanan368aa692022-09-27 11:46:48 +0100285/*
286 * Returns a slice of 'blob' from index 'n1' to 'n2' in 'rettv'. The length of
287 * the blob is 'len'. Returns an empty blob if the indexes are out of range.
288 */
289 static int
290blob_slice(
291 blob_T *blob,
292 long len,
293 varnumber_T n1,
294 varnumber_T n2,
295 int exclusive,
296 typval_T *rettv)
297{
298 if (n1 < 0)
299 {
300 n1 = len + n1;
301 if (n1 < 0)
302 n1 = 0;
303 }
304 if (n2 < 0)
305 n2 = len + n2;
306 else if (n2 >= len)
307 n2 = len - (exclusive ? 0 : 1);
308 if (exclusive)
309 --n2;
310 if (n1 >= len || n2 < 0 || n1 > n2)
311 {
312 clear_tv(rettv);
313 rettv->v_type = VAR_BLOB;
314 rettv->vval.v_blob = NULL;
315 }
316 else
317 {
318 blob_T *new_blob = blob_alloc();
319 long i;
320
321 if (new_blob != NULL)
322 {
323 if (ga_grow(&new_blob->bv_ga, n2 - n1 + 1) == FAIL)
324 {
325 blob_free(new_blob);
326 return FAIL;
327 }
328 new_blob->bv_ga.ga_len = n2 - n1 + 1;
329 for (i = n1; i <= n2; i++)
330 blob_set(new_blob, i - n1, blob_get(blob, i));
331
332 clear_tv(rettv);
333 rettv_blob_set(rettv, new_blob);
334 }
335 }
336
337 return OK;
338}
339
340/*
341 * Return the byte value in 'blob' at index 'idx' in 'rettv'. If the index is
342 * too big or negative that is an error. The length of the blob is 'len'.
343 */
344 static int
345blob_index(
346 blob_T *blob,
347 int len,
348 varnumber_T idx,
349 typval_T *rettv)
350{
351 // The resulting variable is a byte value.
352 // If the index is too big or negative that is an error.
353 if (idx < 0)
354 idx = len + idx;
355 if (idx < len && idx >= 0)
356 {
357 int v = blob_get(blob, idx);
358
359 clear_tv(rettv);
360 rettv->v_type = VAR_NUMBER;
361 rettv->vval.v_number = v;
362 }
363 else
364 {
365 semsg(_(e_blob_index_out_of_range_nr), idx);
366 return FAIL;
367 }
368
369 return OK;
370}
371
Bram Moolenaarcfc30232021-04-11 20:26:34 +0200372 int
373blob_slice_or_index(
374 blob_T *blob,
375 int is_range,
376 varnumber_T n1,
377 varnumber_T n2,
378 int exclusive,
379 typval_T *rettv)
380{
Yegappan Lakshmanan368aa692022-09-27 11:46:48 +0100381 long len = blob_len(blob);
Bram Moolenaarcfc30232021-04-11 20:26:34 +0200382
383 if (is_range)
Yegappan Lakshmanan368aa692022-09-27 11:46:48 +0100384 return blob_slice(blob, len, n1, n2, exclusive, rettv);
Bram Moolenaarcfc30232021-04-11 20:26:34 +0200385 else
Yegappan Lakshmanan368aa692022-09-27 11:46:48 +0100386 return blob_index(blob, len, n1, rettv);
Bram Moolenaarcfc30232021-04-11 20:26:34 +0200387 return OK;
388}
389
Bram Moolenaar9f9fe372019-07-27 23:12:12 +0200390/*
Bram Moolenaar0e3ff192021-04-14 20:35:23 +0200391 * Check if "n1"- is a valid index for a blobl with length "bloblen".
392 */
393 int
Bram Moolenaarbd6406f2021-04-14 21:30:06 +0200394check_blob_index(long bloblen, varnumber_T n1, int quiet)
Bram Moolenaar0e3ff192021-04-14 20:35:23 +0200395{
396 if (n1 < 0 || n1 > bloblen)
397 {
398 if (!quiet)
Bram Moolenaar460ae5d2022-01-01 14:19:49 +0000399 semsg(_(e_blob_index_out_of_range_nr), n1);
Bram Moolenaar0e3ff192021-04-14 20:35:23 +0200400 return FAIL;
401 }
402 return OK;
403}
404
405/*
406 * Check if "n1"-"n2" is a valid range for a blob with length "bloblen".
407 */
408 int
409check_blob_range(long bloblen, varnumber_T n1, varnumber_T n2, int quiet)
410{
411 if (n2 < 0 || n2 >= bloblen || n2 < n1)
412 {
413 if (!quiet)
Bram Moolenaar460ae5d2022-01-01 14:19:49 +0000414 semsg(_(e_blob_index_out_of_range_nr), n2);
Bram Moolenaar0e3ff192021-04-14 20:35:23 +0200415 return FAIL;
416 }
417 return OK;
418}
419
420/*
Bram Moolenaar68452172021-04-12 21:21:02 +0200421 * Set bytes "n1" to "n2" (inclusive) in "dest" to the value of "src".
422 * Caller must make sure "src" is a blob.
423 * Returns FAIL if the number of bytes does not match.
424 */
425 int
426blob_set_range(blob_T *dest, long n1, long n2, typval_T *src)
427{
428 int il, ir;
429
430 if (n2 - n1 + 1 != blob_len(src->vval.v_blob))
431 {
Bram Moolenaarf1474d82021-12-31 19:59:55 +0000432 emsg(_(e_blob_value_does_not_have_right_number_of_bytes));
Bram Moolenaar68452172021-04-12 21:21:02 +0200433 return FAIL;
434 }
435
436 ir = 0;
437 for (il = n1; il <= n2; il++)
438 blob_set(dest, il, blob_get(src->vval.v_blob, ir++));
439 return OK;
440}
441
442/*
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000443 * "add(blob, item)" function
444 */
445 void
446blob_add(typval_T *argvars, typval_T *rettv)
447{
448 blob_T *b = argvars[0].vval.v_blob;
449 int error = FALSE;
450 varnumber_T n;
451
452 if (b == NULL)
453 {
454 if (in_vim9script())
455 emsg(_(e_cannot_add_to_null_blob));
456 return;
457 }
458
459 if (value_check_lock(b->bv_lock, (char_u *)N_("add() argument"), TRUE))
460 return;
461
462 n = tv_get_number_chk(&argvars[1], &error);
463 if (error)
464 return;
465
466 ga_append(&b->bv_ga, (int)n);
467 copy_tv(&argvars[0], rettv);
468}
469
470/*
471 * "remove({blob}, {idx} [, {end}])" function
Bram Moolenaar9f9fe372019-07-27 23:12:12 +0200472 */
473 void
Sean Dewar80d73952021-08-04 19:25:54 +0200474blob_remove(typval_T *argvars, typval_T *rettv, char_u *arg_errmsg)
Bram Moolenaar9f9fe372019-07-27 23:12:12 +0200475{
Sean Dewar80d73952021-08-04 19:25:54 +0200476 blob_T *b = argvars[0].vval.v_blob;
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000477 blob_T *newblob;
Bram Moolenaar9f9fe372019-07-27 23:12:12 +0200478 int error = FALSE;
Yegappan Lakshmanan83494b42021-07-20 17:51:51 +0200479 long idx;
Bram Moolenaar9f9fe372019-07-27 23:12:12 +0200480 long end;
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000481 int len;
482 char_u *p;
Bram Moolenaar9f9fe372019-07-27 23:12:12 +0200483
Sean Dewar80d73952021-08-04 19:25:54 +0200484 if (b != NULL && value_check_lock(b->bv_lock, arg_errmsg, TRUE))
485 return;
486
Yegappan Lakshmanan83494b42021-07-20 17:51:51 +0200487 idx = (long)tv_get_number_chk(&argvars[1], &error);
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000488 if (error)
489 return;
Bram Moolenaar9f9fe372019-07-27 23:12:12 +0200490
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000491 len = blob_len(b);
492
493 if (idx < 0)
494 // count from the end
495 idx = len + idx;
496 if (idx < 0 || idx >= len)
497 {
Bram Moolenaar460ae5d2022-01-01 14:19:49 +0000498 semsg(_(e_blob_index_out_of_range_nr), idx);
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000499 return;
500 }
501 if (argvars[2].v_type == VAR_UNKNOWN)
502 {
503 // Remove one item, return its value.
504 p = (char_u *)b->bv_ga.ga_data;
505 rettv->vval.v_number = (varnumber_T) *(p + idx);
506 mch_memmove(p + idx, p + idx + 1, (size_t)len - idx - 1);
507 --b->bv_ga.ga_len;
508 return;
509 }
510
511 // Remove range of items, return blob with values.
512 end = (long)tv_get_number_chk(&argvars[2], &error);
513 if (error)
514 return;
515 if (end < 0)
516 // count from the end
517 end = len + end;
518 if (end >= len || idx > end)
519 {
Bram Moolenaar460ae5d2022-01-01 14:19:49 +0000520 semsg(_(e_blob_index_out_of_range_nr), end);
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000521 return;
522 }
523 newblob = blob_alloc();
524 if (newblob == NULL)
525 return;
526 newblob->bv_ga.ga_len = end - idx + 1;
527 if (ga_grow(&newblob->bv_ga, end - idx + 1) == FAIL)
528 {
529 vim_free(newblob);
530 return;
531 }
532 p = (char_u *)b->bv_ga.ga_data;
533 mch_memmove((char_u *)newblob->bv_ga.ga_data, p + idx,
534 (size_t)(end - idx + 1));
535 ++newblob->bv_refcount;
536 rettv->v_type = VAR_BLOB;
537 rettv->vval.v_blob = newblob;
538
539 if (len - end - 1 > 0)
540 mch_memmove(p + idx, p + end + 1, (size_t)(len - end - 1));
541 b->bv_ga.ga_len -= end - idx + 1;
542}
543
544/*
545 * Implementation of map() and filter() for a Blob. Apply "expr" to every
546 * number in Blob "blob_arg" and return the result in "rettv".
547 */
548 void
549blob_filter_map(
550 blob_T *blob_arg,
551 filtermap_T filtermap,
552 typval_T *expr,
553 typval_T *rettv)
554{
555 blob_T *b;
556 int i;
557 typval_T tv;
558 varnumber_T val;
559 blob_T *b_ret;
560 int idx = 0;
561 int rem;
Bram Moolenaar82418262022-09-28 16:16:15 +0100562 typval_T newtv;
563 funccall_T *fc;
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000564
565 if (filtermap == FILTERMAP_MAPNEW)
566 {
567 rettv->v_type = VAR_BLOB;
568 rettv->vval.v_blob = NULL;
569 }
570 if ((b = blob_arg) == NULL)
571 return;
572
573 b_ret = b;
574 if (filtermap == FILTERMAP_MAPNEW)
575 {
576 if (blob_copy(b, rettv) == FAIL)
577 return;
578 b_ret = rettv->vval.v_blob;
579 }
580
581 // set_vim_var_nr() doesn't set the type
582 set_vim_var_type(VV_KEY, VAR_NUMBER);
583
Bram Moolenaar82418262022-09-28 16:16:15 +0100584 // Create one funccal_T for all eval_expr_typval() calls.
585 fc = eval_expr_get_funccal(expr, &newtv);
586
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000587 for (i = 0; i < b->bv_ga.ga_len; i++)
588 {
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000589 tv.v_type = VAR_NUMBER;
590 val = blob_get(b, i);
591 tv.vval.v_number = val;
592 set_vim_var_nr(VV_KEY, idx);
Bram Moolenaar82418262022-09-28 16:16:15 +0100593 if (filter_map_one(&tv, expr, filtermap, fc, &newtv, &rem) == FAIL
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000594 || did_emsg)
595 break;
596 if (newtv.v_type != VAR_NUMBER && newtv.v_type != VAR_BOOL)
Bram Moolenaar9f9fe372019-07-27 23:12:12 +0200597 {
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000598 clear_tv(&newtv);
Bram Moolenaar460ae5d2022-01-01 14:19:49 +0000599 emsg(_(e_invalid_operation_for_blob));
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000600 break;
601 }
602 if (filtermap != FILTERMAP_FILTER)
603 {
604 if (newtv.vval.v_number != val)
605 blob_set(b_ret, i, newtv.vval.v_number);
606 }
607 else if (rem)
608 {
609 char_u *p = (char_u *)blob_arg->bv_ga.ga_data;
610
611 mch_memmove(p + i, p + i + 1,
612 (size_t)b->bv_ga.ga_len - i - 1);
613 --b->bv_ga.ga_len;
614 --i;
615 }
616 ++idx;
617 }
Bram Moolenaar82418262022-09-28 16:16:15 +0100618
619 if (fc != NULL)
620 remove_funccal();
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000621}
622
623/*
624 * "insert(blob, {item} [, {idx}])" function
625 */
626 void
627blob_insert_func(typval_T *argvars, typval_T *rettv)
628{
629 blob_T *b = argvars[0].vval.v_blob;
630 long before = 0;
631 int error = FALSE;
632 int val, len;
633 char_u *p;
634
635 if (b == NULL)
636 {
637 if (in_vim9script())
638 emsg(_(e_cannot_add_to_null_blob));
639 return;
640 }
641
642 if (value_check_lock(b->bv_lock, (char_u *)N_("insert() argument"), TRUE))
643 return;
644
645 len = blob_len(b);
646 if (argvars[2].v_type != VAR_UNKNOWN)
647 {
648 before = (long)tv_get_number_chk(&argvars[2], &error);
649 if (error)
650 return; // type error; errmsg already given
651 if (before < 0 || before > len)
652 {
Bram Moolenaar436b5ad2021-12-31 22:49:24 +0000653 semsg(_(e_invalid_argument_str), tv_get_string(&argvars[2]));
Bram Moolenaar9f9fe372019-07-27 23:12:12 +0200654 return;
655 }
Bram Moolenaar9f9fe372019-07-27 23:12:12 +0200656 }
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000657 val = tv_get_number_chk(&argvars[1], &error);
658 if (error)
659 return;
660 if (val < 0 || val > 255)
661 {
Bram Moolenaar436b5ad2021-12-31 22:49:24 +0000662 semsg(_(e_invalid_argument_str), tv_get_string(&argvars[1]));
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000663 return;
664 }
665
666 if (ga_grow(&b->bv_ga, 1) == FAIL)
667 return;
668 p = (char_u *)b->bv_ga.ga_data;
669 mch_memmove(p + before + 1, p + before, (size_t)len - before);
670 *(p + before) = val;
671 ++b->bv_ga.ga_len;
672
673 copy_tv(&argvars[0], rettv);
674}
675
676/*
Bram Moolenaarf1c60d42022-09-22 17:07:00 +0100677 * Implementaion of reduce() for Blob "argvars[0]" using the function "expr"
678 * starting with the optional initial value "argvars[2]" and return the result
679 * in "rettv".
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000680 */
681 void
682blob_reduce(
683 typval_T *argvars,
Bram Moolenaarf1c60d42022-09-22 17:07:00 +0100684 typval_T *expr,
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000685 typval_T *rettv)
686{
687 blob_T *b = argvars[0].vval.v_blob;
688 int called_emsg_start = called_emsg;
689 int r;
690 typval_T initial;
691 typval_T argv[3];
692 int i;
693
694 if (argvars[2].v_type == VAR_UNKNOWN)
695 {
696 if (b == NULL || b->bv_ga.ga_len == 0)
697 {
Bram Moolenaar460ae5d2022-01-01 14:19:49 +0000698 semsg(_(e_reduce_of_an_empty_str_with_no_initial_value), "Blob");
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000699 return;
700 }
701 initial.v_type = VAR_NUMBER;
702 initial.vval.v_number = blob_get(b, 0);
703 i = 1;
704 }
Yegappan Lakshmanan8deb2b32022-09-02 15:15:27 +0100705 else if (check_for_number_arg(argvars, 2) == FAIL)
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000706 return;
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000707 else
708 {
709 initial = argvars[2];
710 i = 0;
711 }
712
713 copy_tv(&initial, rettv);
714 if (b == NULL)
715 return;
716
717 for ( ; i < b->bv_ga.ga_len; i++)
718 {
719 argv[0] = *rettv;
720 argv[1].v_type = VAR_NUMBER;
721 argv[1].vval.v_number = blob_get(b, i);
Bram Moolenaarf1c60d42022-09-22 17:07:00 +0100722
Bram Moolenaar82418262022-09-28 16:16:15 +0100723 r = eval_expr_typval(expr, argv, 2, NULL, rettv);
Bram Moolenaarf1c60d42022-09-22 17:07:00 +0100724
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000725 clear_tv(&argv[0]);
726 if (r == FAIL || called_emsg != called_emsg_start)
727 return;
728 }
729}
730
731/*
732 * "reverse({blob})" function
733 */
734 void
735blob_reverse(blob_T *b, typval_T *rettv)
736{
737 int i, len = blob_len(b);
738
739 for (i = 0; i < len / 2; i++)
740 {
741 int tmp = blob_get(b, i);
742
743 blob_set(b, i, blob_get(b, len - i - 1));
744 blob_set(b, len - i - 1, tmp);
745 }
746 rettv_blob_set(rettv, b);
Bram Moolenaar9f9fe372019-07-27 23:12:12 +0200747}
748
Yegappan Lakshmanan5dfe4672021-09-14 17:54:30 +0200749/*
750 * blob2list() function
751 */
752 void
753f_blob2list(typval_T *argvars, typval_T *rettv)
754{
755 blob_T *blob;
756 list_T *l;
757 int i;
758
759 if (rettv_list_alloc(rettv) == FAIL)
760 return;
761
762 if (check_for_blob_arg(argvars, 0) == FAIL)
763 return;
764
765 blob = argvars->vval.v_blob;
766 l = rettv->vval.v_list;
767 for (i = 0; i < blob_len(blob); i++)
768 list_append_number(l, blob_get(blob, i));
769}
770
771/*
772 * list2blob() function
773 */
774 void
775f_list2blob(typval_T *argvars, typval_T *rettv)
776{
777 list_T *l;
778 listitem_T *li;
779 blob_T *blob;
780
781 if (rettv_blob_alloc(rettv) == FAIL)
782 return;
783 blob = rettv->vval.v_blob;
784
785 if (check_for_list_arg(argvars, 0) == FAIL)
786 return;
787
788 l = argvars->vval.v_list;
789 if (l == NULL)
790 return;
791
kuuote04b7b4b2021-12-03 13:57:00 +0000792 CHECK_LIST_MATERIALIZE(l);
Yegappan Lakshmanan5dfe4672021-09-14 17:54:30 +0200793 FOR_ALL_LIST_ITEMS(l, li)
794 {
795 int error;
796 varnumber_T n;
797
798 error = FALSE;
799 n = tv_get_number_chk(&li->li_tv, &error);
800 if (error == TRUE || n < 0 || n > 255)
801 {
802 if (!error)
803 semsg(_(e_invalid_value_for_blob_nr), n);
804 ga_clear(&blob->bv_ga);
805 return;
806 }
807 ga_append(&blob->bv_ga, n);
808 }
809}
810
Bram Moolenaarc667da52019-11-30 20:52:27 +0100811#endif // defined(FEAT_EVAL)