blob: e4d23d260bfed175175c1b2b27daf9828b370a1c [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;
562
563 if (filtermap == FILTERMAP_MAPNEW)
564 {
565 rettv->v_type = VAR_BLOB;
566 rettv->vval.v_blob = NULL;
567 }
568 if ((b = blob_arg) == NULL)
569 return;
570
571 b_ret = b;
572 if (filtermap == FILTERMAP_MAPNEW)
573 {
574 if (blob_copy(b, rettv) == FAIL)
575 return;
576 b_ret = rettv->vval.v_blob;
577 }
578
579 // set_vim_var_nr() doesn't set the type
580 set_vim_var_type(VV_KEY, VAR_NUMBER);
581
582 for (i = 0; i < b->bv_ga.ga_len; i++)
583 {
584 typval_T newtv;
585
586 tv.v_type = VAR_NUMBER;
587 val = blob_get(b, i);
588 tv.vval.v_number = val;
589 set_vim_var_nr(VV_KEY, idx);
590 if (filter_map_one(&tv, expr, filtermap, &newtv, &rem) == FAIL
591 || did_emsg)
592 break;
593 if (newtv.v_type != VAR_NUMBER && newtv.v_type != VAR_BOOL)
Bram Moolenaar9f9fe372019-07-27 23:12:12 +0200594 {
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000595 clear_tv(&newtv);
Bram Moolenaar460ae5d2022-01-01 14:19:49 +0000596 emsg(_(e_invalid_operation_for_blob));
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000597 break;
598 }
599 if (filtermap != FILTERMAP_FILTER)
600 {
601 if (newtv.vval.v_number != val)
602 blob_set(b_ret, i, newtv.vval.v_number);
603 }
604 else if (rem)
605 {
606 char_u *p = (char_u *)blob_arg->bv_ga.ga_data;
607
608 mch_memmove(p + i, p + i + 1,
609 (size_t)b->bv_ga.ga_len - i - 1);
610 --b->bv_ga.ga_len;
611 --i;
612 }
613 ++idx;
614 }
615}
616
617/*
618 * "insert(blob, {item} [, {idx}])" function
619 */
620 void
621blob_insert_func(typval_T *argvars, typval_T *rettv)
622{
623 blob_T *b = argvars[0].vval.v_blob;
624 long before = 0;
625 int error = FALSE;
626 int val, len;
627 char_u *p;
628
629 if (b == NULL)
630 {
631 if (in_vim9script())
632 emsg(_(e_cannot_add_to_null_blob));
633 return;
634 }
635
636 if (value_check_lock(b->bv_lock, (char_u *)N_("insert() argument"), TRUE))
637 return;
638
639 len = blob_len(b);
640 if (argvars[2].v_type != VAR_UNKNOWN)
641 {
642 before = (long)tv_get_number_chk(&argvars[2], &error);
643 if (error)
644 return; // type error; errmsg already given
645 if (before < 0 || before > len)
646 {
Bram Moolenaar436b5ad2021-12-31 22:49:24 +0000647 semsg(_(e_invalid_argument_str), tv_get_string(&argvars[2]));
Bram Moolenaar9f9fe372019-07-27 23:12:12 +0200648 return;
649 }
Bram Moolenaar9f9fe372019-07-27 23:12:12 +0200650 }
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000651 val = tv_get_number_chk(&argvars[1], &error);
652 if (error)
653 return;
654 if (val < 0 || val > 255)
655 {
Bram Moolenaar436b5ad2021-12-31 22:49:24 +0000656 semsg(_(e_invalid_argument_str), tv_get_string(&argvars[1]));
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000657 return;
658 }
659
660 if (ga_grow(&b->bv_ga, 1) == FAIL)
661 return;
662 p = (char_u *)b->bv_ga.ga_data;
663 mch_memmove(p + before + 1, p + before, (size_t)len - before);
664 *(p + before) = val;
665 ++b->bv_ga.ga_len;
666
667 copy_tv(&argvars[0], rettv);
668}
669
670/*
Bram Moolenaarf1c60d42022-09-22 17:07:00 +0100671 * Implementaion of reduce() for Blob "argvars[0]" using the function "expr"
672 * starting with the optional initial value "argvars[2]" and return the result
673 * in "rettv".
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000674 */
675 void
676blob_reduce(
677 typval_T *argvars,
Bram Moolenaarf1c60d42022-09-22 17:07:00 +0100678 typval_T *expr,
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000679 typval_T *rettv)
680{
681 blob_T *b = argvars[0].vval.v_blob;
682 int called_emsg_start = called_emsg;
683 int r;
684 typval_T initial;
685 typval_T argv[3];
686 int i;
687
688 if (argvars[2].v_type == VAR_UNKNOWN)
689 {
690 if (b == NULL || b->bv_ga.ga_len == 0)
691 {
Bram Moolenaar460ae5d2022-01-01 14:19:49 +0000692 semsg(_(e_reduce_of_an_empty_str_with_no_initial_value), "Blob");
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000693 return;
694 }
695 initial.v_type = VAR_NUMBER;
696 initial.vval.v_number = blob_get(b, 0);
697 i = 1;
698 }
Yegappan Lakshmanan8deb2b32022-09-02 15:15:27 +0100699 else if (check_for_number_arg(argvars, 2) == FAIL)
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000700 return;
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000701 else
702 {
703 initial = argvars[2];
704 i = 0;
705 }
706
707 copy_tv(&initial, rettv);
708 if (b == NULL)
709 return;
710
711 for ( ; i < b->bv_ga.ga_len; i++)
712 {
713 argv[0] = *rettv;
714 argv[1].v_type = VAR_NUMBER;
715 argv[1].vval.v_number = blob_get(b, i);
Bram Moolenaarf1c60d42022-09-22 17:07:00 +0100716
717 r = eval_expr_typval(expr, argv, 2, rettv);
718
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000719 clear_tv(&argv[0]);
720 if (r == FAIL || called_emsg != called_emsg_start)
721 return;
722 }
723}
724
725/*
726 * "reverse({blob})" function
727 */
728 void
729blob_reverse(blob_T *b, typval_T *rettv)
730{
731 int i, len = blob_len(b);
732
733 for (i = 0; i < len / 2; i++)
734 {
735 int tmp = blob_get(b, i);
736
737 blob_set(b, i, blob_get(b, len - i - 1));
738 blob_set(b, len - i - 1, tmp);
739 }
740 rettv_blob_set(rettv, b);
Bram Moolenaar9f9fe372019-07-27 23:12:12 +0200741}
742
Yegappan Lakshmanan5dfe4672021-09-14 17:54:30 +0200743/*
744 * blob2list() function
745 */
746 void
747f_blob2list(typval_T *argvars, typval_T *rettv)
748{
749 blob_T *blob;
750 list_T *l;
751 int i;
752
753 if (rettv_list_alloc(rettv) == FAIL)
754 return;
755
756 if (check_for_blob_arg(argvars, 0) == FAIL)
757 return;
758
759 blob = argvars->vval.v_blob;
760 l = rettv->vval.v_list;
761 for (i = 0; i < blob_len(blob); i++)
762 list_append_number(l, blob_get(blob, i));
763}
764
765/*
766 * list2blob() function
767 */
768 void
769f_list2blob(typval_T *argvars, typval_T *rettv)
770{
771 list_T *l;
772 listitem_T *li;
773 blob_T *blob;
774
775 if (rettv_blob_alloc(rettv) == FAIL)
776 return;
777 blob = rettv->vval.v_blob;
778
779 if (check_for_list_arg(argvars, 0) == FAIL)
780 return;
781
782 l = argvars->vval.v_list;
783 if (l == NULL)
784 return;
785
kuuote04b7b4b2021-12-03 13:57:00 +0000786 CHECK_LIST_MATERIALIZE(l);
Yegappan Lakshmanan5dfe4672021-09-14 17:54:30 +0200787 FOR_ALL_LIST_ITEMS(l, li)
788 {
789 int error;
790 varnumber_T n;
791
792 error = FALSE;
793 n = tv_get_number_chk(&li->li_tv, &error);
794 if (error == TRUE || n < 0 || n > 255)
795 {
796 if (!error)
797 semsg(_(e_invalid_value_for_blob_nr), n);
798 ga_clear(&blob->bv_ga);
799 return;
800 }
801 ga_append(&blob->bv_ga, n);
802 }
803}
804
Bram Moolenaarc667da52019-11-30 20:52:27 +0100805#endif // defined(FEAT_EVAL)