blob: 1387a8e6531dd2d729d7b75d32e4c585fa8582b5 [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{
Bram Moolenaarc799fe22019-05-28 23:08:19 +020025 blob_T *blob = ALLOC_CLEAR_ONE(blob_T);
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{
63 int ret = OK;
64
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 to->vval.v_blob = NULL;
69 else if (rettv_blob_alloc(to) == FAIL)
70 ret = FAIL;
71 else
72 {
Bram Moolenaar8a7d6542020-01-26 15:56:19 +010073 int len = from->bv_ga.ga_len;
Bram Moolenaardd29ea12019-01-23 21:56:21 +010074
75 if (len > 0)
Bram Moolenaara5be9b62019-01-24 12:31:44 +010076 {
Bram Moolenaardd29ea12019-01-23 21:56:21 +010077 to->vval.v_blob->bv_ga.ga_data =
Bram Moolenaar8a7d6542020-01-26 15:56:19 +010078 vim_memsave(from->bv_ga.ga_data, len);
Bram Moolenaara5be9b62019-01-24 12:31:44 +010079 if (to->vval.v_blob->bv_ga.ga_data == NULL)
80 len = 0;
81 }
Bram Moolenaardd29ea12019-01-23 21:56:21 +010082 to->vval.v_blob->bv_ga.ga_len = len;
Bram Moolenaar66fa5fd2020-10-19 20:21:03 +020083 to->vval.v_blob->bv_ga.ga_maxlen = len;
Bram Moolenaardd29ea12019-01-23 21:56:21 +010084 }
85 return ret;
86}
87
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010088 void
89blob_free(blob_T *b)
90{
91 ga_clear(&b->bv_ga);
92 vim_free(b);
93}
94
95/*
96 * Unreference a blob: decrement the reference count and free it when it
97 * becomes zero.
98 */
99 void
100blob_unref(blob_T *b)
101{
102 if (b != NULL && --b->bv_refcount <= 0)
103 blob_free(b);
104}
105
106/*
107 * Get the length of data.
108 */
109 long
110blob_len(blob_T *b)
111{
112 if (b == NULL)
113 return 0L;
114 return b->bv_ga.ga_len;
115}
116
117/*
118 * Get byte "idx" in blob "b".
119 * Caller must check that "idx" is valid.
120 */
Bram Moolenaara5be9b62019-01-24 12:31:44 +0100121 int
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +0100122blob_get(blob_T *b, int idx)
123{
124 return ((char_u*)b->bv_ga.ga_data)[idx];
125}
126
127/*
Bram Moolenaar51e93322021-04-17 20:44:56 +0200128 * Store one byte "byte" in blob "blob" at "idx".
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +0100129 * Caller must make sure that "idx" is valid.
130 */
131 void
Bram Moolenaar51e93322021-04-17 20:44:56 +0200132blob_set(blob_T *blob, int idx, int byte)
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +0100133{
Bram Moolenaar51e93322021-04-17 20:44:56 +0200134 ((char_u*)blob->bv_ga.ga_data)[idx] = byte;
135}
136
137/*
138 * Store one byte "byte" in blob "blob" at "idx".
139 * Append one byte if needed.
140 */
141 void
142blob_set_append(blob_T *blob, int idx, int byte)
143{
144 garray_T *gap = &blob->bv_ga;
145
146 // Allow for appending a byte. Setting a byte beyond
147 // the end is an error otherwise.
148 if (idx < gap->ga_len
149 || (idx == gap->ga_len && ga_grow(gap, 1) == OK))
150 {
151 blob_set(blob, idx, byte);
152 if (idx == gap->ga_len)
153 ++gap->ga_len;
154 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +0100155}
156
157/*
158 * Return TRUE when two blobs have exactly the same values.
159 */
160 int
161blob_equal(
162 blob_T *b1,
163 blob_T *b2)
164{
Bram Moolenaarc0f5a782019-01-13 15:16:13 +0100165 int i;
166 int len1 = blob_len(b1);
167 int len2 = blob_len(b2);
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +0100168
Bram Moolenaarc0f5a782019-01-13 15:16:13 +0100169 // empty and NULL are considered the same
170 if (len1 == 0 && len2 == 0)
171 return TRUE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +0100172 if (b1 == b2)
173 return TRUE;
Bram Moolenaarc0f5a782019-01-13 15:16:13 +0100174 if (len1 != len2)
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +0100175 return FALSE;
176
177 for (i = 0; i < b1->bv_ga.ga_len; i++)
178 if (blob_get(b1, i) != blob_get(b2, i)) return FALSE;
179 return TRUE;
180}
181
182/*
183 * Read "blob" from file "fd".
184 * Return OK or FAIL.
185 */
186 int
187read_blob(FILE *fd, blob_T *blob)
188{
189 struct stat st;
190
191 if (fstat(fileno(fd), &st) < 0)
192 return FAIL;
193 if (ga_grow(&blob->bv_ga, st.st_size) == FAIL)
194 return FAIL;
195 blob->bv_ga.ga_len = st.st_size;
196 if (fread(blob->bv_ga.ga_data, 1, blob->bv_ga.ga_len, fd)
197 < (size_t)blob->bv_ga.ga_len)
198 return FAIL;
199 return OK;
200}
201
202/*
203 * Write "blob" to file "fd".
204 * Return OK or FAIL.
205 */
206 int
207write_blob(FILE *fd, blob_T *blob)
208{
209 if (fwrite(blob->bv_ga.ga_data, 1, blob->bv_ga.ga_len, fd)
210 < (size_t)blob->bv_ga.ga_len)
211 {
Bram Moolenaar40bcec12021-12-05 22:19:27 +0000212 emsg(_(e_error_while_writing));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +0100213 return FAIL;
214 }
215 return OK;
216}
217
Bram Moolenaar8c8b8bb2019-01-13 17:48:04 +0100218/*
Bram Moolenaar4131fd52019-01-17 16:32:53 +0100219 * Convert a blob to a readable form: "0z00112233.44556677.8899"
Bram Moolenaar8c8b8bb2019-01-13 17:48:04 +0100220 */
221 char_u *
222blob2string(blob_T *blob, char_u **tofree, char_u *numbuf)
223{
224 int i;
225 garray_T ga;
226
227 if (blob == NULL)
228 {
229 *tofree = NULL;
Bram Moolenaar4131fd52019-01-17 16:32:53 +0100230 return (char_u *)"0z";
Bram Moolenaar8c8b8bb2019-01-13 17:48:04 +0100231 }
232
233 // Store bytes in the growarray.
234 ga_init2(&ga, 1, 4000);
Bram Moolenaar4131fd52019-01-17 16:32:53 +0100235 ga_concat(&ga, (char_u *)"0z");
Bram Moolenaar8c8b8bb2019-01-13 17:48:04 +0100236 for (i = 0; i < blob_len(blob); i++)
237 {
Bram Moolenaar4131fd52019-01-17 16:32:53 +0100238 if (i > 0 && (i & 3) == 0)
239 ga_concat(&ga, (char_u *)".");
240 vim_snprintf((char *)numbuf, NUMBUFLEN, "%02X", (int)blob_get(blob, i));
Bram Moolenaar8c8b8bb2019-01-13 17:48:04 +0100241 ga_concat(&ga, numbuf);
242 }
Yegappan Lakshmananbc404bf2021-12-19 19:19:31 +0000243 ga_append(&ga, NUL); // append a NUL at the end
Bram Moolenaar8c8b8bb2019-01-13 17:48:04 +0100244 *tofree = ga.ga_data;
245 return *tofree;
246}
247
248/*
249 * Convert a string variable, in the format of blob2string(), to a blob.
250 * Return NULL when conversion failed.
251 */
252 blob_T *
253string2blob(char_u *str)
254{
255 blob_T *blob = blob_alloc();
256 char_u *s = str;
257
Bram Moolenaare142a942019-03-19 23:03:27 +0100258 if (blob == NULL)
259 return NULL;
Bram Moolenaar4131fd52019-01-17 16:32:53 +0100260 if (s[0] != '0' || (s[1] != 'z' && s[1] != 'Z'))
Bram Moolenaar8c8b8bb2019-01-13 17:48:04 +0100261 goto failed;
Bram Moolenaar4131fd52019-01-17 16:32:53 +0100262 s += 2;
263 while (vim_isxdigit(*s))
Bram Moolenaar8c8b8bb2019-01-13 17:48:04 +0100264 {
Bram Moolenaar4131fd52019-01-17 16:32:53 +0100265 if (!vim_isxdigit(s[1]))
Bram Moolenaar8c8b8bb2019-01-13 17:48:04 +0100266 goto failed;
Bram Moolenaar4131fd52019-01-17 16:32:53 +0100267 ga_append(&blob->bv_ga, (hex2nr(s[0]) << 4) + hex2nr(s[1]));
268 s += 2;
269 if (*s == '.' && vim_isxdigit(s[1]))
270 ++s;
Bram Moolenaar8c8b8bb2019-01-13 17:48:04 +0100271 }
Bram Moolenaar4131fd52019-01-17 16:32:53 +0100272 if (*skipwhite(s) != NUL)
273 goto failed; // text after final digit
Bram Moolenaar8c8b8bb2019-01-13 17:48:04 +0100274
275 ++blob->bv_refcount;
276 return blob;
277
278failed:
279 blob_free(blob);
280 return NULL;
281}
282
Bram Moolenaarcfc30232021-04-11 20:26:34 +0200283 int
284blob_slice_or_index(
285 blob_T *blob,
286 int is_range,
287 varnumber_T n1,
288 varnumber_T n2,
289 int exclusive,
290 typval_T *rettv)
291{
292 long len = blob_len(blob);
293
294 if (is_range)
295 {
296 // The resulting variable is a sub-blob. If the indexes
297 // are out of range the result is empty.
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 else
338 {
339 // The resulting variable is a byte value.
340 // If the index is too big or negative that is an error.
341 if (n1 < 0)
342 n1 = len + n1;
343 if (n1 < len && n1 >= 0)
344 {
345 int v = blob_get(blob, n1);
346
347 clear_tv(rettv);
348 rettv->v_type = VAR_NUMBER;
349 rettv->vval.v_number = v;
350 }
351 else
352 {
353 semsg(_(e_blobidx), n1);
354 return FAIL;
355 }
356 }
357 return OK;
358}
359
Bram Moolenaar9f9fe372019-07-27 23:12:12 +0200360/*
Bram Moolenaar0e3ff192021-04-14 20:35:23 +0200361 * Check if "n1"- is a valid index for a blobl with length "bloblen".
362 */
363 int
Bram Moolenaarbd6406f2021-04-14 21:30:06 +0200364check_blob_index(long bloblen, varnumber_T n1, int quiet)
Bram Moolenaar0e3ff192021-04-14 20:35:23 +0200365{
366 if (n1 < 0 || n1 > bloblen)
367 {
368 if (!quiet)
369 semsg(_(e_blobidx), n1);
370 return FAIL;
371 }
372 return OK;
373}
374
375/*
376 * Check if "n1"-"n2" is a valid range for a blob with length "bloblen".
377 */
378 int
379check_blob_range(long bloblen, varnumber_T n1, varnumber_T n2, int quiet)
380{
381 if (n2 < 0 || n2 >= bloblen || n2 < n1)
382 {
383 if (!quiet)
384 semsg(_(e_blobidx), n2);
385 return FAIL;
386 }
387 return OK;
388}
389
390/*
Bram Moolenaar68452172021-04-12 21:21:02 +0200391 * Set bytes "n1" to "n2" (inclusive) in "dest" to the value of "src".
392 * Caller must make sure "src" is a blob.
393 * Returns FAIL if the number of bytes does not match.
394 */
395 int
396blob_set_range(blob_T *dest, long n1, long n2, typval_T *src)
397{
398 int il, ir;
399
400 if (n2 - n1 + 1 != blob_len(src->vval.v_blob))
401 {
402 emsg(_("E972: Blob value does not have the right number of bytes"));
403 return FAIL;
404 }
405
406 ir = 0;
407 for (il = n1; il <= n2; il++)
408 blob_set(dest, il, blob_get(src->vval.v_blob, ir++));
409 return OK;
410}
411
412/*
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000413 * "add(blob, item)" function
414 */
415 void
416blob_add(typval_T *argvars, typval_T *rettv)
417{
418 blob_T *b = argvars[0].vval.v_blob;
419 int error = FALSE;
420 varnumber_T n;
421
422 if (b == NULL)
423 {
424 if (in_vim9script())
425 emsg(_(e_cannot_add_to_null_blob));
426 return;
427 }
428
429 if (value_check_lock(b->bv_lock, (char_u *)N_("add() argument"), TRUE))
430 return;
431
432 n = tv_get_number_chk(&argvars[1], &error);
433 if (error)
434 return;
435
436 ga_append(&b->bv_ga, (int)n);
437 copy_tv(&argvars[0], rettv);
438}
439
440/*
441 * "remove({blob}, {idx} [, {end}])" function
Bram Moolenaar9f9fe372019-07-27 23:12:12 +0200442 */
443 void
Sean Dewar80d73952021-08-04 19:25:54 +0200444blob_remove(typval_T *argvars, typval_T *rettv, char_u *arg_errmsg)
Bram Moolenaar9f9fe372019-07-27 23:12:12 +0200445{
Sean Dewar80d73952021-08-04 19:25:54 +0200446 blob_T *b = argvars[0].vval.v_blob;
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000447 blob_T *newblob;
Bram Moolenaar9f9fe372019-07-27 23:12:12 +0200448 int error = FALSE;
Yegappan Lakshmanan83494b42021-07-20 17:51:51 +0200449 long idx;
Bram Moolenaar9f9fe372019-07-27 23:12:12 +0200450 long end;
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000451 int len;
452 char_u *p;
Bram Moolenaar9f9fe372019-07-27 23:12:12 +0200453
Sean Dewar80d73952021-08-04 19:25:54 +0200454 if (b != NULL && value_check_lock(b->bv_lock, arg_errmsg, TRUE))
455 return;
456
Yegappan Lakshmanan83494b42021-07-20 17:51:51 +0200457 idx = (long)tv_get_number_chk(&argvars[1], &error);
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000458 if (error)
459 return;
Bram Moolenaar9f9fe372019-07-27 23:12:12 +0200460
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000461 len = blob_len(b);
462
463 if (idx < 0)
464 // count from the end
465 idx = len + idx;
466 if (idx < 0 || idx >= len)
467 {
468 semsg(_(e_blobidx), idx);
469 return;
470 }
471 if (argvars[2].v_type == VAR_UNKNOWN)
472 {
473 // Remove one item, return its value.
474 p = (char_u *)b->bv_ga.ga_data;
475 rettv->vval.v_number = (varnumber_T) *(p + idx);
476 mch_memmove(p + idx, p + idx + 1, (size_t)len - idx - 1);
477 --b->bv_ga.ga_len;
478 return;
479 }
480
481 // Remove range of items, return blob with values.
482 end = (long)tv_get_number_chk(&argvars[2], &error);
483 if (error)
484 return;
485 if (end < 0)
486 // count from the end
487 end = len + end;
488 if (end >= len || idx > end)
489 {
490 semsg(_(e_blobidx), end);
491 return;
492 }
493 newblob = blob_alloc();
494 if (newblob == NULL)
495 return;
496 newblob->bv_ga.ga_len = end - idx + 1;
497 if (ga_grow(&newblob->bv_ga, end - idx + 1) == FAIL)
498 {
499 vim_free(newblob);
500 return;
501 }
502 p = (char_u *)b->bv_ga.ga_data;
503 mch_memmove((char_u *)newblob->bv_ga.ga_data, p + idx,
504 (size_t)(end - idx + 1));
505 ++newblob->bv_refcount;
506 rettv->v_type = VAR_BLOB;
507 rettv->vval.v_blob = newblob;
508
509 if (len - end - 1 > 0)
510 mch_memmove(p + idx, p + end + 1, (size_t)(len - end - 1));
511 b->bv_ga.ga_len -= end - idx + 1;
512}
513
514/*
515 * Implementation of map() and filter() for a Blob. Apply "expr" to every
516 * number in Blob "blob_arg" and return the result in "rettv".
517 */
518 void
519blob_filter_map(
520 blob_T *blob_arg,
521 filtermap_T filtermap,
522 typval_T *expr,
523 typval_T *rettv)
524{
525 blob_T *b;
526 int i;
527 typval_T tv;
528 varnumber_T val;
529 blob_T *b_ret;
530 int idx = 0;
531 int rem;
532
533 if (filtermap == FILTERMAP_MAPNEW)
534 {
535 rettv->v_type = VAR_BLOB;
536 rettv->vval.v_blob = NULL;
537 }
538 if ((b = blob_arg) == NULL)
539 return;
540
541 b_ret = b;
542 if (filtermap == FILTERMAP_MAPNEW)
543 {
544 if (blob_copy(b, rettv) == FAIL)
545 return;
546 b_ret = rettv->vval.v_blob;
547 }
548
549 // set_vim_var_nr() doesn't set the type
550 set_vim_var_type(VV_KEY, VAR_NUMBER);
551
552 for (i = 0; i < b->bv_ga.ga_len; i++)
553 {
554 typval_T newtv;
555
556 tv.v_type = VAR_NUMBER;
557 val = blob_get(b, i);
558 tv.vval.v_number = val;
559 set_vim_var_nr(VV_KEY, idx);
560 if (filter_map_one(&tv, expr, filtermap, &newtv, &rem) == FAIL
561 || did_emsg)
562 break;
563 if (newtv.v_type != VAR_NUMBER && newtv.v_type != VAR_BOOL)
Bram Moolenaar9f9fe372019-07-27 23:12:12 +0200564 {
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000565 clear_tv(&newtv);
566 emsg(_(e_invalblob));
567 break;
568 }
569 if (filtermap != FILTERMAP_FILTER)
570 {
571 if (newtv.vval.v_number != val)
572 blob_set(b_ret, i, newtv.vval.v_number);
573 }
574 else if (rem)
575 {
576 char_u *p = (char_u *)blob_arg->bv_ga.ga_data;
577
578 mch_memmove(p + i, p + i + 1,
579 (size_t)b->bv_ga.ga_len - i - 1);
580 --b->bv_ga.ga_len;
581 --i;
582 }
583 ++idx;
584 }
585}
586
587/*
588 * "insert(blob, {item} [, {idx}])" function
589 */
590 void
591blob_insert_func(typval_T *argvars, typval_T *rettv)
592{
593 blob_T *b = argvars[0].vval.v_blob;
594 long before = 0;
595 int error = FALSE;
596 int val, len;
597 char_u *p;
598
599 if (b == NULL)
600 {
601 if (in_vim9script())
602 emsg(_(e_cannot_add_to_null_blob));
603 return;
604 }
605
606 if (value_check_lock(b->bv_lock, (char_u *)N_("insert() argument"), TRUE))
607 return;
608
609 len = blob_len(b);
610 if (argvars[2].v_type != VAR_UNKNOWN)
611 {
612 before = (long)tv_get_number_chk(&argvars[2], &error);
613 if (error)
614 return; // type error; errmsg already given
615 if (before < 0 || before > len)
616 {
617 semsg(_(e_invarg2), tv_get_string(&argvars[2]));
Bram Moolenaar9f9fe372019-07-27 23:12:12 +0200618 return;
619 }
Bram Moolenaar9f9fe372019-07-27 23:12:12 +0200620 }
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000621 val = tv_get_number_chk(&argvars[1], &error);
622 if (error)
623 return;
624 if (val < 0 || val > 255)
625 {
626 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
627 return;
628 }
629
630 if (ga_grow(&b->bv_ga, 1) == FAIL)
631 return;
632 p = (char_u *)b->bv_ga.ga_data;
633 mch_memmove(p + before + 1, p + before, (size_t)len - before);
634 *(p + before) = val;
635 ++b->bv_ga.ga_len;
636
637 copy_tv(&argvars[0], rettv);
638}
639
640/*
641 * reduce() Blob argvars[0] using the function 'funcname' with arguments in
642 * 'funcexe' starting with the initial value argvars[2] and return the result
643 * in 'rettv'.
644 */
645 void
646blob_reduce(
647 typval_T *argvars,
648 char_u *func_name,
649 funcexe_T *funcexe,
650 typval_T *rettv)
651{
652 blob_T *b = argvars[0].vval.v_blob;
653 int called_emsg_start = called_emsg;
654 int r;
655 typval_T initial;
656 typval_T argv[3];
657 int i;
658
659 if (argvars[2].v_type == VAR_UNKNOWN)
660 {
661 if (b == NULL || b->bv_ga.ga_len == 0)
662 {
663 semsg(_(e_reduceempty), "Blob");
664 return;
665 }
666 initial.v_type = VAR_NUMBER;
667 initial.vval.v_number = blob_get(b, 0);
668 i = 1;
669 }
670 else if (argvars[2].v_type != VAR_NUMBER)
671 {
672 emsg(_(e_number_expected));
673 return;
674 }
675 else
676 {
677 initial = argvars[2];
678 i = 0;
679 }
680
681 copy_tv(&initial, rettv);
682 if (b == NULL)
683 return;
684
685 for ( ; i < b->bv_ga.ga_len; i++)
686 {
687 argv[0] = *rettv;
688 argv[1].v_type = VAR_NUMBER;
689 argv[1].vval.v_number = blob_get(b, i);
690 r = call_func(func_name, -1, rettv, 2, argv, funcexe);
691 clear_tv(&argv[0]);
692 if (r == FAIL || called_emsg != called_emsg_start)
693 return;
694 }
695}
696
697/*
698 * "reverse({blob})" function
699 */
700 void
701blob_reverse(blob_T *b, typval_T *rettv)
702{
703 int i, len = blob_len(b);
704
705 for (i = 0; i < len / 2; i++)
706 {
707 int tmp = blob_get(b, i);
708
709 blob_set(b, i, blob_get(b, len - i - 1));
710 blob_set(b, len - i - 1, tmp);
711 }
712 rettv_blob_set(rettv, b);
Bram Moolenaar9f9fe372019-07-27 23:12:12 +0200713}
714
Yegappan Lakshmanan5dfe4672021-09-14 17:54:30 +0200715/*
716 * blob2list() function
717 */
718 void
719f_blob2list(typval_T *argvars, typval_T *rettv)
720{
721 blob_T *blob;
722 list_T *l;
723 int i;
724
725 if (rettv_list_alloc(rettv) == FAIL)
726 return;
727
728 if (check_for_blob_arg(argvars, 0) == FAIL)
729 return;
730
731 blob = argvars->vval.v_blob;
732 l = rettv->vval.v_list;
733 for (i = 0; i < blob_len(blob); i++)
734 list_append_number(l, blob_get(blob, i));
735}
736
737/*
738 * list2blob() function
739 */
740 void
741f_list2blob(typval_T *argvars, typval_T *rettv)
742{
743 list_T *l;
744 listitem_T *li;
745 blob_T *blob;
746
747 if (rettv_blob_alloc(rettv) == FAIL)
748 return;
749 blob = rettv->vval.v_blob;
750
751 if (check_for_list_arg(argvars, 0) == FAIL)
752 return;
753
754 l = argvars->vval.v_list;
755 if (l == NULL)
756 return;
757
kuuote04b7b4b2021-12-03 13:57:00 +0000758 CHECK_LIST_MATERIALIZE(l);
Yegappan Lakshmanan5dfe4672021-09-14 17:54:30 +0200759 FOR_ALL_LIST_ITEMS(l, li)
760 {
761 int error;
762 varnumber_T n;
763
764 error = FALSE;
765 n = tv_get_number_chk(&li->li_tv, &error);
766 if (error == TRUE || n < 0 || n > 255)
767 {
768 if (!error)
769 semsg(_(e_invalid_value_for_blob_nr), n);
770 ga_clear(&blob->bv_ga);
771 return;
772 }
773 ga_append(&blob->bv_ga, n);
774 }
775}
776
Bram Moolenaarc667da52019-11-30 20:52:27 +0100777#endif // defined(FEAT_EVAL)