blob: a94316c13f56fc5b91a5cbe25eb6ebf7ebb819a6 [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/*
K.Takata11df3ae2022-10-19 14:02:40 +0100185 * Read blob from file "fd".
186 * Caller has allocated a blob in "rettv".
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +0100187 * Return OK or FAIL.
188 */
189 int
K.Takata11df3ae2022-10-19 14:02:40 +0100190read_blob(FILE *fd, typval_T *rettv, off_T offset, off_T size_arg)
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +0100191{
K.Takata11df3ae2022-10-19 14:02:40 +0100192 blob_T *blob = rettv->vval.v_blob;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +0100193 struct stat st;
K.Takata11df3ae2022-10-19 14:02:40 +0100194 int whence;
195 off_T size = size_arg;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +0100196
197 if (fstat(fileno(fd), &st) < 0)
K.Takata11df3ae2022-10-19 14:02:40 +0100198 return FAIL; // can't read the file, error
199
200 if (offset >= 0)
201 {
202 if (size == -1)
203 // size may become negative, checked below
204 size = st.st_size - offset;
205 whence = SEEK_SET;
206 }
207 else
208 {
209 if (size == -1)
210 size = -offset;
211 whence = SEEK_END;
212 }
213 // Trying to read bytes that aren't there results in an empty blob, not an
214 // error.
K.Takata43625762022-10-20 13:28:51 +0100215 if (size <= 0 || (
216#ifdef S_ISCHR
217 !S_ISCHR(st.st_mode) &&
218#endif
219 size > st.st_size))
K.Takata11df3ae2022-10-19 14:02:40 +0100220 return OK;
K.Takata43625762022-10-20 13:28:51 +0100221 if (offset != 0 && vim_fseek(fd, offset, whence) != 0)
K.Takata11df3ae2022-10-19 14:02:40 +0100222 return OK;
223
224 if (ga_grow(&blob->bv_ga, (int)size) == FAIL)
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +0100225 return FAIL;
K.Takata11df3ae2022-10-19 14:02:40 +0100226 blob->bv_ga.ga_len = (int)size;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +0100227 if (fread(blob->bv_ga.ga_data, 1, blob->bv_ga.ga_len, fd)
228 < (size_t)blob->bv_ga.ga_len)
K.Takata11df3ae2022-10-19 14:02:40 +0100229 {
230 // An empty blob is returned on error.
231 blob_free(rettv->vval.v_blob);
232 rettv->vval.v_blob = NULL;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +0100233 return FAIL;
K.Takata11df3ae2022-10-19 14:02:40 +0100234 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +0100235 return OK;
236}
237
238/*
239 * Write "blob" to file "fd".
240 * Return OK or FAIL.
241 */
242 int
243write_blob(FILE *fd, blob_T *blob)
244{
245 if (fwrite(blob->bv_ga.ga_data, 1, blob->bv_ga.ga_len, fd)
246 < (size_t)blob->bv_ga.ga_len)
247 {
Bram Moolenaar40bcec12021-12-05 22:19:27 +0000248 emsg(_(e_error_while_writing));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +0100249 return FAIL;
250 }
251 return OK;
252}
253
Bram Moolenaar8c8b8bb2019-01-13 17:48:04 +0100254/*
Bram Moolenaar4131fd52019-01-17 16:32:53 +0100255 * Convert a blob to a readable form: "0z00112233.44556677.8899"
Bram Moolenaar8c8b8bb2019-01-13 17:48:04 +0100256 */
257 char_u *
258blob2string(blob_T *blob, char_u **tofree, char_u *numbuf)
259{
260 int i;
261 garray_T ga;
262
263 if (blob == NULL)
264 {
265 *tofree = NULL;
Bram Moolenaar4131fd52019-01-17 16:32:53 +0100266 return (char_u *)"0z";
Bram Moolenaar8c8b8bb2019-01-13 17:48:04 +0100267 }
268
269 // Store bytes in the growarray.
270 ga_init2(&ga, 1, 4000);
Bram Moolenaar4131fd52019-01-17 16:32:53 +0100271 ga_concat(&ga, (char_u *)"0z");
Bram Moolenaar8c8b8bb2019-01-13 17:48:04 +0100272 for (i = 0; i < blob_len(blob); i++)
273 {
Bram Moolenaar4131fd52019-01-17 16:32:53 +0100274 if (i > 0 && (i & 3) == 0)
275 ga_concat(&ga, (char_u *)".");
=?UTF-8?q?Dundar=20G=C3=B6c?=420fabc2022-01-28 15:28:04 +0000276 vim_snprintf((char *)numbuf, NUMBUFLEN, "%02X", blob_get(blob, i));
Bram Moolenaar8c8b8bb2019-01-13 17:48:04 +0100277 ga_concat(&ga, numbuf);
278 }
Yegappan Lakshmananbc404bf2021-12-19 19:19:31 +0000279 ga_append(&ga, NUL); // append a NUL at the end
Bram Moolenaar8c8b8bb2019-01-13 17:48:04 +0100280 *tofree = ga.ga_data;
281 return *tofree;
282}
283
284/*
285 * Convert a string variable, in the format of blob2string(), to a blob.
286 * Return NULL when conversion failed.
287 */
288 blob_T *
289string2blob(char_u *str)
290{
291 blob_T *blob = blob_alloc();
292 char_u *s = str;
293
Bram Moolenaare142a942019-03-19 23:03:27 +0100294 if (blob == NULL)
295 return NULL;
Bram Moolenaar4131fd52019-01-17 16:32:53 +0100296 if (s[0] != '0' || (s[1] != 'z' && s[1] != 'Z'))
Bram Moolenaar8c8b8bb2019-01-13 17:48:04 +0100297 goto failed;
Bram Moolenaar4131fd52019-01-17 16:32:53 +0100298 s += 2;
299 while (vim_isxdigit(*s))
Bram Moolenaar8c8b8bb2019-01-13 17:48:04 +0100300 {
Bram Moolenaar4131fd52019-01-17 16:32:53 +0100301 if (!vim_isxdigit(s[1]))
Bram Moolenaar8c8b8bb2019-01-13 17:48:04 +0100302 goto failed;
Bram Moolenaar4131fd52019-01-17 16:32:53 +0100303 ga_append(&blob->bv_ga, (hex2nr(s[0]) << 4) + hex2nr(s[1]));
304 s += 2;
305 if (*s == '.' && vim_isxdigit(s[1]))
306 ++s;
Bram Moolenaar8c8b8bb2019-01-13 17:48:04 +0100307 }
Bram Moolenaar4131fd52019-01-17 16:32:53 +0100308 if (*skipwhite(s) != NUL)
309 goto failed; // text after final digit
Bram Moolenaar8c8b8bb2019-01-13 17:48:04 +0100310
311 ++blob->bv_refcount;
312 return blob;
313
314failed:
315 blob_free(blob);
316 return NULL;
317}
318
Yegappan Lakshmanan368aa692022-09-27 11:46:48 +0100319/*
320 * Returns a slice of 'blob' from index 'n1' to 'n2' in 'rettv'. The length of
321 * the blob is 'len'. Returns an empty blob if the indexes are out of range.
322 */
323 static int
324blob_slice(
325 blob_T *blob,
326 long len,
327 varnumber_T n1,
328 varnumber_T n2,
329 int exclusive,
330 typval_T *rettv)
331{
332 if (n1 < 0)
333 {
334 n1 = len + n1;
335 if (n1 < 0)
336 n1 = 0;
337 }
338 if (n2 < 0)
339 n2 = len + n2;
340 else if (n2 >= len)
341 n2 = len - (exclusive ? 0 : 1);
342 if (exclusive)
343 --n2;
344 if (n1 >= len || n2 < 0 || n1 > n2)
345 {
346 clear_tv(rettv);
347 rettv->v_type = VAR_BLOB;
348 rettv->vval.v_blob = NULL;
349 }
350 else
351 {
352 blob_T *new_blob = blob_alloc();
353 long i;
354
355 if (new_blob != NULL)
356 {
357 if (ga_grow(&new_blob->bv_ga, n2 - n1 + 1) == FAIL)
358 {
359 blob_free(new_blob);
360 return FAIL;
361 }
362 new_blob->bv_ga.ga_len = n2 - n1 + 1;
363 for (i = n1; i <= n2; i++)
364 blob_set(new_blob, i - n1, blob_get(blob, i));
365
366 clear_tv(rettv);
367 rettv_blob_set(rettv, new_blob);
368 }
369 }
370
371 return OK;
372}
373
374/*
375 * Return the byte value in 'blob' at index 'idx' in 'rettv'. If the index is
376 * too big or negative that is an error. The length of the blob is 'len'.
377 */
378 static int
379blob_index(
380 blob_T *blob,
381 int len,
382 varnumber_T idx,
383 typval_T *rettv)
384{
385 // The resulting variable is a byte value.
386 // If the index is too big or negative that is an error.
387 if (idx < 0)
388 idx = len + idx;
389 if (idx < len && idx >= 0)
390 {
391 int v = blob_get(blob, idx);
392
393 clear_tv(rettv);
394 rettv->v_type = VAR_NUMBER;
395 rettv->vval.v_number = v;
396 }
397 else
398 {
399 semsg(_(e_blob_index_out_of_range_nr), idx);
400 return FAIL;
401 }
402
403 return OK;
404}
405
Bram Moolenaarcfc30232021-04-11 20:26:34 +0200406 int
407blob_slice_or_index(
408 blob_T *blob,
409 int is_range,
410 varnumber_T n1,
411 varnumber_T n2,
412 int exclusive,
413 typval_T *rettv)
414{
Yegappan Lakshmanan368aa692022-09-27 11:46:48 +0100415 long len = blob_len(blob);
Bram Moolenaarcfc30232021-04-11 20:26:34 +0200416
417 if (is_range)
Yegappan Lakshmanan368aa692022-09-27 11:46:48 +0100418 return blob_slice(blob, len, n1, n2, exclusive, rettv);
Bram Moolenaarcfc30232021-04-11 20:26:34 +0200419 else
Yegappan Lakshmanan368aa692022-09-27 11:46:48 +0100420 return blob_index(blob, len, n1, rettv);
Bram Moolenaarcfc30232021-04-11 20:26:34 +0200421 return OK;
422}
423
Bram Moolenaar9f9fe372019-07-27 23:12:12 +0200424/*
Bram Moolenaar0e3ff192021-04-14 20:35:23 +0200425 * Check if "n1"- is a valid index for a blobl with length "bloblen".
426 */
427 int
Bram Moolenaarbd6406f2021-04-14 21:30:06 +0200428check_blob_index(long bloblen, varnumber_T n1, int quiet)
Bram Moolenaar0e3ff192021-04-14 20:35:23 +0200429{
430 if (n1 < 0 || n1 > bloblen)
431 {
432 if (!quiet)
Bram Moolenaar460ae5d2022-01-01 14:19:49 +0000433 semsg(_(e_blob_index_out_of_range_nr), n1);
Bram Moolenaar0e3ff192021-04-14 20:35:23 +0200434 return FAIL;
435 }
436 return OK;
437}
438
439/*
440 * Check if "n1"-"n2" is a valid range for a blob with length "bloblen".
441 */
442 int
443check_blob_range(long bloblen, varnumber_T n1, varnumber_T n2, int quiet)
444{
445 if (n2 < 0 || n2 >= bloblen || n2 < n1)
446 {
447 if (!quiet)
Bram Moolenaar460ae5d2022-01-01 14:19:49 +0000448 semsg(_(e_blob_index_out_of_range_nr), n2);
Bram Moolenaar0e3ff192021-04-14 20:35:23 +0200449 return FAIL;
450 }
451 return OK;
452}
453
454/*
Bram Moolenaar68452172021-04-12 21:21:02 +0200455 * Set bytes "n1" to "n2" (inclusive) in "dest" to the value of "src".
456 * Caller must make sure "src" is a blob.
457 * Returns FAIL if the number of bytes does not match.
458 */
459 int
460blob_set_range(blob_T *dest, long n1, long n2, typval_T *src)
461{
462 int il, ir;
463
464 if (n2 - n1 + 1 != blob_len(src->vval.v_blob))
465 {
Bram Moolenaarf1474d82021-12-31 19:59:55 +0000466 emsg(_(e_blob_value_does_not_have_right_number_of_bytes));
Bram Moolenaar68452172021-04-12 21:21:02 +0200467 return FAIL;
468 }
469
470 ir = 0;
471 for (il = n1; il <= n2; il++)
472 blob_set(dest, il, blob_get(src->vval.v_blob, ir++));
473 return OK;
474}
475
476/*
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000477 * "add(blob, item)" function
478 */
479 void
480blob_add(typval_T *argvars, typval_T *rettv)
481{
482 blob_T *b = argvars[0].vval.v_blob;
483 int error = FALSE;
484 varnumber_T n;
485
486 if (b == NULL)
487 {
488 if (in_vim9script())
489 emsg(_(e_cannot_add_to_null_blob));
490 return;
491 }
492
493 if (value_check_lock(b->bv_lock, (char_u *)N_("add() argument"), TRUE))
494 return;
495
496 n = tv_get_number_chk(&argvars[1], &error);
497 if (error)
498 return;
499
500 ga_append(&b->bv_ga, (int)n);
501 copy_tv(&argvars[0], rettv);
502}
503
504/*
505 * "remove({blob}, {idx} [, {end}])" function
Bram Moolenaar9f9fe372019-07-27 23:12:12 +0200506 */
507 void
Sean Dewar80d73952021-08-04 19:25:54 +0200508blob_remove(typval_T *argvars, typval_T *rettv, char_u *arg_errmsg)
Bram Moolenaar9f9fe372019-07-27 23:12:12 +0200509{
Sean Dewar80d73952021-08-04 19:25:54 +0200510 blob_T *b = argvars[0].vval.v_blob;
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000511 blob_T *newblob;
Bram Moolenaar9f9fe372019-07-27 23:12:12 +0200512 int error = FALSE;
Yegappan Lakshmanan83494b42021-07-20 17:51:51 +0200513 long idx;
Bram Moolenaar9f9fe372019-07-27 23:12:12 +0200514 long end;
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000515 int len;
516 char_u *p;
Bram Moolenaar9f9fe372019-07-27 23:12:12 +0200517
Sean Dewar80d73952021-08-04 19:25:54 +0200518 if (b != NULL && value_check_lock(b->bv_lock, arg_errmsg, TRUE))
519 return;
520
Yegappan Lakshmanan83494b42021-07-20 17:51:51 +0200521 idx = (long)tv_get_number_chk(&argvars[1], &error);
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000522 if (error)
523 return;
Bram Moolenaar9f9fe372019-07-27 23:12:12 +0200524
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000525 len = blob_len(b);
526
527 if (idx < 0)
528 // count from the end
529 idx = len + idx;
530 if (idx < 0 || idx >= len)
531 {
Bram Moolenaar460ae5d2022-01-01 14:19:49 +0000532 semsg(_(e_blob_index_out_of_range_nr), idx);
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000533 return;
534 }
535 if (argvars[2].v_type == VAR_UNKNOWN)
536 {
537 // Remove one item, return its value.
538 p = (char_u *)b->bv_ga.ga_data;
539 rettv->vval.v_number = (varnumber_T) *(p + idx);
540 mch_memmove(p + idx, p + idx + 1, (size_t)len - idx - 1);
541 --b->bv_ga.ga_len;
542 return;
543 }
544
545 // Remove range of items, return blob with values.
546 end = (long)tv_get_number_chk(&argvars[2], &error);
547 if (error)
548 return;
549 if (end < 0)
550 // count from the end
551 end = len + end;
552 if (end >= len || idx > end)
553 {
Bram Moolenaar460ae5d2022-01-01 14:19:49 +0000554 semsg(_(e_blob_index_out_of_range_nr), end);
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000555 return;
556 }
557 newblob = blob_alloc();
558 if (newblob == NULL)
559 return;
560 newblob->bv_ga.ga_len = end - idx + 1;
561 if (ga_grow(&newblob->bv_ga, end - idx + 1) == FAIL)
562 {
563 vim_free(newblob);
564 return;
565 }
566 p = (char_u *)b->bv_ga.ga_data;
567 mch_memmove((char_u *)newblob->bv_ga.ga_data, p + idx,
568 (size_t)(end - idx + 1));
569 ++newblob->bv_refcount;
570 rettv->v_type = VAR_BLOB;
571 rettv->vval.v_blob = newblob;
572
573 if (len - end - 1 > 0)
574 mch_memmove(p + idx, p + end + 1, (size_t)(len - end - 1));
575 b->bv_ga.ga_len -= end - idx + 1;
576}
577
578/*
579 * Implementation of map() and filter() for a Blob. Apply "expr" to every
580 * number in Blob "blob_arg" and return the result in "rettv".
581 */
582 void
583blob_filter_map(
584 blob_T *blob_arg,
585 filtermap_T filtermap,
586 typval_T *expr,
587 typval_T *rettv)
588{
589 blob_T *b;
590 int i;
591 typval_T tv;
592 varnumber_T val;
593 blob_T *b_ret;
594 int idx = 0;
595 int rem;
Bram Moolenaar82418262022-09-28 16:16:15 +0100596 typval_T newtv;
597 funccall_T *fc;
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000598
599 if (filtermap == FILTERMAP_MAPNEW)
600 {
601 rettv->v_type = VAR_BLOB;
602 rettv->vval.v_blob = NULL;
603 }
604 if ((b = blob_arg) == NULL)
605 return;
606
607 b_ret = b;
608 if (filtermap == FILTERMAP_MAPNEW)
609 {
610 if (blob_copy(b, rettv) == FAIL)
611 return;
612 b_ret = rettv->vval.v_blob;
613 }
614
615 // set_vim_var_nr() doesn't set the type
616 set_vim_var_type(VV_KEY, VAR_NUMBER);
617
Bram Moolenaar82418262022-09-28 16:16:15 +0100618 // Create one funccal_T for all eval_expr_typval() calls.
619 fc = eval_expr_get_funccal(expr, &newtv);
620
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000621 for (i = 0; i < b->bv_ga.ga_len; i++)
622 {
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000623 tv.v_type = VAR_NUMBER;
624 val = blob_get(b, i);
625 tv.vval.v_number = val;
626 set_vim_var_nr(VV_KEY, idx);
Bram Moolenaar82418262022-09-28 16:16:15 +0100627 if (filter_map_one(&tv, expr, filtermap, fc, &newtv, &rem) == FAIL
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000628 || did_emsg)
629 break;
630 if (newtv.v_type != VAR_NUMBER && newtv.v_type != VAR_BOOL)
Bram Moolenaar9f9fe372019-07-27 23:12:12 +0200631 {
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000632 clear_tv(&newtv);
Bram Moolenaar460ae5d2022-01-01 14:19:49 +0000633 emsg(_(e_invalid_operation_for_blob));
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000634 break;
635 }
636 if (filtermap != FILTERMAP_FILTER)
637 {
638 if (newtv.vval.v_number != val)
639 blob_set(b_ret, i, newtv.vval.v_number);
640 }
641 else if (rem)
642 {
643 char_u *p = (char_u *)blob_arg->bv_ga.ga_data;
644
645 mch_memmove(p + i, p + i + 1,
646 (size_t)b->bv_ga.ga_len - i - 1);
647 --b->bv_ga.ga_len;
648 --i;
649 }
650 ++idx;
651 }
Bram Moolenaar82418262022-09-28 16:16:15 +0100652
653 if (fc != NULL)
654 remove_funccal();
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000655}
656
657/*
658 * "insert(blob, {item} [, {idx}])" function
659 */
660 void
661blob_insert_func(typval_T *argvars, typval_T *rettv)
662{
663 blob_T *b = argvars[0].vval.v_blob;
664 long before = 0;
665 int error = FALSE;
666 int val, len;
667 char_u *p;
668
669 if (b == NULL)
670 {
671 if (in_vim9script())
672 emsg(_(e_cannot_add_to_null_blob));
673 return;
674 }
675
676 if (value_check_lock(b->bv_lock, (char_u *)N_("insert() argument"), TRUE))
677 return;
678
679 len = blob_len(b);
680 if (argvars[2].v_type != VAR_UNKNOWN)
681 {
682 before = (long)tv_get_number_chk(&argvars[2], &error);
683 if (error)
684 return; // type error; errmsg already given
685 if (before < 0 || before > len)
686 {
Bram Moolenaar436b5ad2021-12-31 22:49:24 +0000687 semsg(_(e_invalid_argument_str), tv_get_string(&argvars[2]));
Bram Moolenaar9f9fe372019-07-27 23:12:12 +0200688 return;
689 }
Bram Moolenaar9f9fe372019-07-27 23:12:12 +0200690 }
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000691 val = tv_get_number_chk(&argvars[1], &error);
692 if (error)
693 return;
694 if (val < 0 || val > 255)
695 {
Bram Moolenaar436b5ad2021-12-31 22:49:24 +0000696 semsg(_(e_invalid_argument_str), tv_get_string(&argvars[1]));
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000697 return;
698 }
699
700 if (ga_grow(&b->bv_ga, 1) == FAIL)
701 return;
702 p = (char_u *)b->bv_ga.ga_data;
703 mch_memmove(p + before + 1, p + before, (size_t)len - before);
704 *(p + before) = val;
705 ++b->bv_ga.ga_len;
706
707 copy_tv(&argvars[0], rettv);
708}
709
710/*
Bram Moolenaarf1c60d42022-09-22 17:07:00 +0100711 * Implementaion of reduce() for Blob "argvars[0]" using the function "expr"
712 * starting with the optional initial value "argvars[2]" and return the result
713 * in "rettv".
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000714 */
715 void
716blob_reduce(
717 typval_T *argvars,
Bram Moolenaarf1c60d42022-09-22 17:07:00 +0100718 typval_T *expr,
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000719 typval_T *rettv)
720{
721 blob_T *b = argvars[0].vval.v_blob;
722 int called_emsg_start = called_emsg;
723 int r;
724 typval_T initial;
725 typval_T argv[3];
726 int i;
727
728 if (argvars[2].v_type == VAR_UNKNOWN)
729 {
730 if (b == NULL || b->bv_ga.ga_len == 0)
731 {
Bram Moolenaar460ae5d2022-01-01 14:19:49 +0000732 semsg(_(e_reduce_of_an_empty_str_with_no_initial_value), "Blob");
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000733 return;
734 }
735 initial.v_type = VAR_NUMBER;
736 initial.vval.v_number = blob_get(b, 0);
737 i = 1;
738 }
Yegappan Lakshmanan8deb2b32022-09-02 15:15:27 +0100739 else if (check_for_number_arg(argvars, 2) == FAIL)
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000740 return;
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000741 else
742 {
743 initial = argvars[2];
744 i = 0;
745 }
746
747 copy_tv(&initial, rettv);
748 if (b == NULL)
749 return;
750
751 for ( ; i < b->bv_ga.ga_len; i++)
752 {
753 argv[0] = *rettv;
754 argv[1].v_type = VAR_NUMBER;
755 argv[1].vval.v_number = blob_get(b, i);
Bram Moolenaarf1c60d42022-09-22 17:07:00 +0100756
Bram Moolenaar82418262022-09-28 16:16:15 +0100757 r = eval_expr_typval(expr, argv, 2, NULL, rettv);
Bram Moolenaarf1c60d42022-09-22 17:07:00 +0100758
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000759 clear_tv(&argv[0]);
760 if (r == FAIL || called_emsg != called_emsg_start)
761 return;
762 }
763}
764
765/*
766 * "reverse({blob})" function
767 */
768 void
769blob_reverse(blob_T *b, typval_T *rettv)
770{
771 int i, len = blob_len(b);
772
773 for (i = 0; i < len / 2; i++)
774 {
775 int tmp = blob_get(b, i);
776
777 blob_set(b, i, blob_get(b, len - i - 1));
778 blob_set(b, len - i - 1, tmp);
779 }
780 rettv_blob_set(rettv, b);
Bram Moolenaar9f9fe372019-07-27 23:12:12 +0200781}
782
Yegappan Lakshmanan5dfe4672021-09-14 17:54:30 +0200783/*
784 * blob2list() function
785 */
786 void
787f_blob2list(typval_T *argvars, typval_T *rettv)
788{
789 blob_T *blob;
790 list_T *l;
791 int i;
792
793 if (rettv_list_alloc(rettv) == FAIL)
794 return;
795
796 if (check_for_blob_arg(argvars, 0) == FAIL)
797 return;
798
799 blob = argvars->vval.v_blob;
800 l = rettv->vval.v_list;
801 for (i = 0; i < blob_len(blob); i++)
802 list_append_number(l, blob_get(blob, i));
803}
804
805/*
806 * list2blob() function
807 */
808 void
809f_list2blob(typval_T *argvars, typval_T *rettv)
810{
811 list_T *l;
812 listitem_T *li;
813 blob_T *blob;
814
815 if (rettv_blob_alloc(rettv) == FAIL)
816 return;
817 blob = rettv->vval.v_blob;
818
819 if (check_for_list_arg(argvars, 0) == FAIL)
820 return;
821
822 l = argvars->vval.v_list;
823 if (l == NULL)
824 return;
825
kuuote04b7b4b2021-12-03 13:57:00 +0000826 CHECK_LIST_MATERIALIZE(l);
Yegappan Lakshmanan5dfe4672021-09-14 17:54:30 +0200827 FOR_ALL_LIST_ITEMS(l, li)
828 {
829 int error;
830 varnumber_T n;
831
832 error = FALSE;
833 n = tv_get_number_chk(&li->li_tv, &error);
834 if (error == TRUE || n < 0 || n > 255)
835 {
836 if (!error)
837 semsg(_(e_invalid_value_for_blob_nr), n);
838 ga_clear(&blob->bv_ga);
839 return;
840 }
841 ga_append(&blob->bv_ga, n);
842 }
843}
844
Bram Moolenaarc667da52019-11-30 20:52:27 +0100845#endif // defined(FEAT_EVAL)