blob: 92efb67ab5ccda3fb5965c08e6c155a108e3e215 [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.
215 if (size < 0 || size > st.st_size)
216 return OK;
217 if (vim_fseek(fd, offset, whence) != 0)
218 return OK;
219
220 if (ga_grow(&blob->bv_ga, (int)size) == FAIL)
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +0100221 return FAIL;
K.Takata11df3ae2022-10-19 14:02:40 +0100222 blob->bv_ga.ga_len = (int)size;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +0100223 if (fread(blob->bv_ga.ga_data, 1, blob->bv_ga.ga_len, fd)
224 < (size_t)blob->bv_ga.ga_len)
K.Takata11df3ae2022-10-19 14:02:40 +0100225 {
226 // An empty blob is returned on error.
227 blob_free(rettv->vval.v_blob);
228 rettv->vval.v_blob = NULL;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +0100229 return FAIL;
K.Takata11df3ae2022-10-19 14:02:40 +0100230 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +0100231 return OK;
232}
233
234/*
235 * Write "blob" to file "fd".
236 * Return OK or FAIL.
237 */
238 int
239write_blob(FILE *fd, blob_T *blob)
240{
241 if (fwrite(blob->bv_ga.ga_data, 1, blob->bv_ga.ga_len, fd)
242 < (size_t)blob->bv_ga.ga_len)
243 {
Bram Moolenaar40bcec12021-12-05 22:19:27 +0000244 emsg(_(e_error_while_writing));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +0100245 return FAIL;
246 }
247 return OK;
248}
249
Bram Moolenaar8c8b8bb2019-01-13 17:48:04 +0100250/*
Bram Moolenaar4131fd52019-01-17 16:32:53 +0100251 * Convert a blob to a readable form: "0z00112233.44556677.8899"
Bram Moolenaar8c8b8bb2019-01-13 17:48:04 +0100252 */
253 char_u *
254blob2string(blob_T *blob, char_u **tofree, char_u *numbuf)
255{
256 int i;
257 garray_T ga;
258
259 if (blob == NULL)
260 {
261 *tofree = NULL;
Bram Moolenaar4131fd52019-01-17 16:32:53 +0100262 return (char_u *)"0z";
Bram Moolenaar8c8b8bb2019-01-13 17:48:04 +0100263 }
264
265 // Store bytes in the growarray.
266 ga_init2(&ga, 1, 4000);
Bram Moolenaar4131fd52019-01-17 16:32:53 +0100267 ga_concat(&ga, (char_u *)"0z");
Bram Moolenaar8c8b8bb2019-01-13 17:48:04 +0100268 for (i = 0; i < blob_len(blob); i++)
269 {
Bram Moolenaar4131fd52019-01-17 16:32:53 +0100270 if (i > 0 && (i & 3) == 0)
271 ga_concat(&ga, (char_u *)".");
=?UTF-8?q?Dundar=20G=C3=B6c?=420fabc2022-01-28 15:28:04 +0000272 vim_snprintf((char *)numbuf, NUMBUFLEN, "%02X", blob_get(blob, i));
Bram Moolenaar8c8b8bb2019-01-13 17:48:04 +0100273 ga_concat(&ga, numbuf);
274 }
Yegappan Lakshmananbc404bf2021-12-19 19:19:31 +0000275 ga_append(&ga, NUL); // append a NUL at the end
Bram Moolenaar8c8b8bb2019-01-13 17:48:04 +0100276 *tofree = ga.ga_data;
277 return *tofree;
278}
279
280/*
281 * Convert a string variable, in the format of blob2string(), to a blob.
282 * Return NULL when conversion failed.
283 */
284 blob_T *
285string2blob(char_u *str)
286{
287 blob_T *blob = blob_alloc();
288 char_u *s = str;
289
Bram Moolenaare142a942019-03-19 23:03:27 +0100290 if (blob == NULL)
291 return NULL;
Bram Moolenaar4131fd52019-01-17 16:32:53 +0100292 if (s[0] != '0' || (s[1] != 'z' && s[1] != 'Z'))
Bram Moolenaar8c8b8bb2019-01-13 17:48:04 +0100293 goto failed;
Bram Moolenaar4131fd52019-01-17 16:32:53 +0100294 s += 2;
295 while (vim_isxdigit(*s))
Bram Moolenaar8c8b8bb2019-01-13 17:48:04 +0100296 {
Bram Moolenaar4131fd52019-01-17 16:32:53 +0100297 if (!vim_isxdigit(s[1]))
Bram Moolenaar8c8b8bb2019-01-13 17:48:04 +0100298 goto failed;
Bram Moolenaar4131fd52019-01-17 16:32:53 +0100299 ga_append(&blob->bv_ga, (hex2nr(s[0]) << 4) + hex2nr(s[1]));
300 s += 2;
301 if (*s == '.' && vim_isxdigit(s[1]))
302 ++s;
Bram Moolenaar8c8b8bb2019-01-13 17:48:04 +0100303 }
Bram Moolenaar4131fd52019-01-17 16:32:53 +0100304 if (*skipwhite(s) != NUL)
305 goto failed; // text after final digit
Bram Moolenaar8c8b8bb2019-01-13 17:48:04 +0100306
307 ++blob->bv_refcount;
308 return blob;
309
310failed:
311 blob_free(blob);
312 return NULL;
313}
314
Yegappan Lakshmanan368aa692022-09-27 11:46:48 +0100315/*
316 * Returns a slice of 'blob' from index 'n1' to 'n2' in 'rettv'. The length of
317 * the blob is 'len'. Returns an empty blob if the indexes are out of range.
318 */
319 static int
320blob_slice(
321 blob_T *blob,
322 long len,
323 varnumber_T n1,
324 varnumber_T n2,
325 int exclusive,
326 typval_T *rettv)
327{
328 if (n1 < 0)
329 {
330 n1 = len + n1;
331 if (n1 < 0)
332 n1 = 0;
333 }
334 if (n2 < 0)
335 n2 = len + n2;
336 else if (n2 >= len)
337 n2 = len - (exclusive ? 0 : 1);
338 if (exclusive)
339 --n2;
340 if (n1 >= len || n2 < 0 || n1 > n2)
341 {
342 clear_tv(rettv);
343 rettv->v_type = VAR_BLOB;
344 rettv->vval.v_blob = NULL;
345 }
346 else
347 {
348 blob_T *new_blob = blob_alloc();
349 long i;
350
351 if (new_blob != NULL)
352 {
353 if (ga_grow(&new_blob->bv_ga, n2 - n1 + 1) == FAIL)
354 {
355 blob_free(new_blob);
356 return FAIL;
357 }
358 new_blob->bv_ga.ga_len = n2 - n1 + 1;
359 for (i = n1; i <= n2; i++)
360 blob_set(new_blob, i - n1, blob_get(blob, i));
361
362 clear_tv(rettv);
363 rettv_blob_set(rettv, new_blob);
364 }
365 }
366
367 return OK;
368}
369
370/*
371 * Return the byte value in 'blob' at index 'idx' in 'rettv'. If the index is
372 * too big or negative that is an error. The length of the blob is 'len'.
373 */
374 static int
375blob_index(
376 blob_T *blob,
377 int len,
378 varnumber_T idx,
379 typval_T *rettv)
380{
381 // The resulting variable is a byte value.
382 // If the index is too big or negative that is an error.
383 if (idx < 0)
384 idx = len + idx;
385 if (idx < len && idx >= 0)
386 {
387 int v = blob_get(blob, idx);
388
389 clear_tv(rettv);
390 rettv->v_type = VAR_NUMBER;
391 rettv->vval.v_number = v;
392 }
393 else
394 {
395 semsg(_(e_blob_index_out_of_range_nr), idx);
396 return FAIL;
397 }
398
399 return OK;
400}
401
Bram Moolenaarcfc30232021-04-11 20:26:34 +0200402 int
403blob_slice_or_index(
404 blob_T *blob,
405 int is_range,
406 varnumber_T n1,
407 varnumber_T n2,
408 int exclusive,
409 typval_T *rettv)
410{
Yegappan Lakshmanan368aa692022-09-27 11:46:48 +0100411 long len = blob_len(blob);
Bram Moolenaarcfc30232021-04-11 20:26:34 +0200412
413 if (is_range)
Yegappan Lakshmanan368aa692022-09-27 11:46:48 +0100414 return blob_slice(blob, len, n1, n2, exclusive, rettv);
Bram Moolenaarcfc30232021-04-11 20:26:34 +0200415 else
Yegappan Lakshmanan368aa692022-09-27 11:46:48 +0100416 return blob_index(blob, len, n1, rettv);
Bram Moolenaarcfc30232021-04-11 20:26:34 +0200417 return OK;
418}
419
Bram Moolenaar9f9fe372019-07-27 23:12:12 +0200420/*
Bram Moolenaar0e3ff192021-04-14 20:35:23 +0200421 * Check if "n1"- is a valid index for a blobl with length "bloblen".
422 */
423 int
Bram Moolenaarbd6406f2021-04-14 21:30:06 +0200424check_blob_index(long bloblen, varnumber_T n1, int quiet)
Bram Moolenaar0e3ff192021-04-14 20:35:23 +0200425{
426 if (n1 < 0 || n1 > bloblen)
427 {
428 if (!quiet)
Bram Moolenaar460ae5d2022-01-01 14:19:49 +0000429 semsg(_(e_blob_index_out_of_range_nr), n1);
Bram Moolenaar0e3ff192021-04-14 20:35:23 +0200430 return FAIL;
431 }
432 return OK;
433}
434
435/*
436 * Check if "n1"-"n2" is a valid range for a blob with length "bloblen".
437 */
438 int
439check_blob_range(long bloblen, varnumber_T n1, varnumber_T n2, int quiet)
440{
441 if (n2 < 0 || n2 >= bloblen || n2 < n1)
442 {
443 if (!quiet)
Bram Moolenaar460ae5d2022-01-01 14:19:49 +0000444 semsg(_(e_blob_index_out_of_range_nr), n2);
Bram Moolenaar0e3ff192021-04-14 20:35:23 +0200445 return FAIL;
446 }
447 return OK;
448}
449
450/*
Bram Moolenaar68452172021-04-12 21:21:02 +0200451 * Set bytes "n1" to "n2" (inclusive) in "dest" to the value of "src".
452 * Caller must make sure "src" is a blob.
453 * Returns FAIL if the number of bytes does not match.
454 */
455 int
456blob_set_range(blob_T *dest, long n1, long n2, typval_T *src)
457{
458 int il, ir;
459
460 if (n2 - n1 + 1 != blob_len(src->vval.v_blob))
461 {
Bram Moolenaarf1474d82021-12-31 19:59:55 +0000462 emsg(_(e_blob_value_does_not_have_right_number_of_bytes));
Bram Moolenaar68452172021-04-12 21:21:02 +0200463 return FAIL;
464 }
465
466 ir = 0;
467 for (il = n1; il <= n2; il++)
468 blob_set(dest, il, blob_get(src->vval.v_blob, ir++));
469 return OK;
470}
471
472/*
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000473 * "add(blob, item)" function
474 */
475 void
476blob_add(typval_T *argvars, typval_T *rettv)
477{
478 blob_T *b = argvars[0].vval.v_blob;
479 int error = FALSE;
480 varnumber_T n;
481
482 if (b == NULL)
483 {
484 if (in_vim9script())
485 emsg(_(e_cannot_add_to_null_blob));
486 return;
487 }
488
489 if (value_check_lock(b->bv_lock, (char_u *)N_("add() argument"), TRUE))
490 return;
491
492 n = tv_get_number_chk(&argvars[1], &error);
493 if (error)
494 return;
495
496 ga_append(&b->bv_ga, (int)n);
497 copy_tv(&argvars[0], rettv);
498}
499
500/*
501 * "remove({blob}, {idx} [, {end}])" function
Bram Moolenaar9f9fe372019-07-27 23:12:12 +0200502 */
503 void
Sean Dewar80d73952021-08-04 19:25:54 +0200504blob_remove(typval_T *argvars, typval_T *rettv, char_u *arg_errmsg)
Bram Moolenaar9f9fe372019-07-27 23:12:12 +0200505{
Sean Dewar80d73952021-08-04 19:25:54 +0200506 blob_T *b = argvars[0].vval.v_blob;
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000507 blob_T *newblob;
Bram Moolenaar9f9fe372019-07-27 23:12:12 +0200508 int error = FALSE;
Yegappan Lakshmanan83494b42021-07-20 17:51:51 +0200509 long idx;
Bram Moolenaar9f9fe372019-07-27 23:12:12 +0200510 long end;
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000511 int len;
512 char_u *p;
Bram Moolenaar9f9fe372019-07-27 23:12:12 +0200513
Sean Dewar80d73952021-08-04 19:25:54 +0200514 if (b != NULL && value_check_lock(b->bv_lock, arg_errmsg, TRUE))
515 return;
516
Yegappan Lakshmanan83494b42021-07-20 17:51:51 +0200517 idx = (long)tv_get_number_chk(&argvars[1], &error);
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000518 if (error)
519 return;
Bram Moolenaar9f9fe372019-07-27 23:12:12 +0200520
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000521 len = blob_len(b);
522
523 if (idx < 0)
524 // count from the end
525 idx = len + idx;
526 if (idx < 0 || idx >= len)
527 {
Bram Moolenaar460ae5d2022-01-01 14:19:49 +0000528 semsg(_(e_blob_index_out_of_range_nr), idx);
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000529 return;
530 }
531 if (argvars[2].v_type == VAR_UNKNOWN)
532 {
533 // Remove one item, return its value.
534 p = (char_u *)b->bv_ga.ga_data;
535 rettv->vval.v_number = (varnumber_T) *(p + idx);
536 mch_memmove(p + idx, p + idx + 1, (size_t)len - idx - 1);
537 --b->bv_ga.ga_len;
538 return;
539 }
540
541 // Remove range of items, return blob with values.
542 end = (long)tv_get_number_chk(&argvars[2], &error);
543 if (error)
544 return;
545 if (end < 0)
546 // count from the end
547 end = len + end;
548 if (end >= len || idx > end)
549 {
Bram Moolenaar460ae5d2022-01-01 14:19:49 +0000550 semsg(_(e_blob_index_out_of_range_nr), end);
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000551 return;
552 }
553 newblob = blob_alloc();
554 if (newblob == NULL)
555 return;
556 newblob->bv_ga.ga_len = end - idx + 1;
557 if (ga_grow(&newblob->bv_ga, end - idx + 1) == FAIL)
558 {
559 vim_free(newblob);
560 return;
561 }
562 p = (char_u *)b->bv_ga.ga_data;
563 mch_memmove((char_u *)newblob->bv_ga.ga_data, p + idx,
564 (size_t)(end - idx + 1));
565 ++newblob->bv_refcount;
566 rettv->v_type = VAR_BLOB;
567 rettv->vval.v_blob = newblob;
568
569 if (len - end - 1 > 0)
570 mch_memmove(p + idx, p + end + 1, (size_t)(len - end - 1));
571 b->bv_ga.ga_len -= end - idx + 1;
572}
573
574/*
575 * Implementation of map() and filter() for a Blob. Apply "expr" to every
576 * number in Blob "blob_arg" and return the result in "rettv".
577 */
578 void
579blob_filter_map(
580 blob_T *blob_arg,
581 filtermap_T filtermap,
582 typval_T *expr,
583 typval_T *rettv)
584{
585 blob_T *b;
586 int i;
587 typval_T tv;
588 varnumber_T val;
589 blob_T *b_ret;
590 int idx = 0;
591 int rem;
Bram Moolenaar82418262022-09-28 16:16:15 +0100592 typval_T newtv;
593 funccall_T *fc;
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000594
595 if (filtermap == FILTERMAP_MAPNEW)
596 {
597 rettv->v_type = VAR_BLOB;
598 rettv->vval.v_blob = NULL;
599 }
600 if ((b = blob_arg) == NULL)
601 return;
602
603 b_ret = b;
604 if (filtermap == FILTERMAP_MAPNEW)
605 {
606 if (blob_copy(b, rettv) == FAIL)
607 return;
608 b_ret = rettv->vval.v_blob;
609 }
610
611 // set_vim_var_nr() doesn't set the type
612 set_vim_var_type(VV_KEY, VAR_NUMBER);
613
Bram Moolenaar82418262022-09-28 16:16:15 +0100614 // Create one funccal_T for all eval_expr_typval() calls.
615 fc = eval_expr_get_funccal(expr, &newtv);
616
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000617 for (i = 0; i < b->bv_ga.ga_len; i++)
618 {
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000619 tv.v_type = VAR_NUMBER;
620 val = blob_get(b, i);
621 tv.vval.v_number = val;
622 set_vim_var_nr(VV_KEY, idx);
Bram Moolenaar82418262022-09-28 16:16:15 +0100623 if (filter_map_one(&tv, expr, filtermap, fc, &newtv, &rem) == FAIL
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000624 || did_emsg)
625 break;
626 if (newtv.v_type != VAR_NUMBER && newtv.v_type != VAR_BOOL)
Bram Moolenaar9f9fe372019-07-27 23:12:12 +0200627 {
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000628 clear_tv(&newtv);
Bram Moolenaar460ae5d2022-01-01 14:19:49 +0000629 emsg(_(e_invalid_operation_for_blob));
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000630 break;
631 }
632 if (filtermap != FILTERMAP_FILTER)
633 {
634 if (newtv.vval.v_number != val)
635 blob_set(b_ret, i, newtv.vval.v_number);
636 }
637 else if (rem)
638 {
639 char_u *p = (char_u *)blob_arg->bv_ga.ga_data;
640
641 mch_memmove(p + i, p + i + 1,
642 (size_t)b->bv_ga.ga_len - i - 1);
643 --b->bv_ga.ga_len;
644 --i;
645 }
646 ++idx;
647 }
Bram Moolenaar82418262022-09-28 16:16:15 +0100648
649 if (fc != NULL)
650 remove_funccal();
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000651}
652
653/*
654 * "insert(blob, {item} [, {idx}])" function
655 */
656 void
657blob_insert_func(typval_T *argvars, typval_T *rettv)
658{
659 blob_T *b = argvars[0].vval.v_blob;
660 long before = 0;
661 int error = FALSE;
662 int val, len;
663 char_u *p;
664
665 if (b == NULL)
666 {
667 if (in_vim9script())
668 emsg(_(e_cannot_add_to_null_blob));
669 return;
670 }
671
672 if (value_check_lock(b->bv_lock, (char_u *)N_("insert() argument"), TRUE))
673 return;
674
675 len = blob_len(b);
676 if (argvars[2].v_type != VAR_UNKNOWN)
677 {
678 before = (long)tv_get_number_chk(&argvars[2], &error);
679 if (error)
680 return; // type error; errmsg already given
681 if (before < 0 || before > len)
682 {
Bram Moolenaar436b5ad2021-12-31 22:49:24 +0000683 semsg(_(e_invalid_argument_str), tv_get_string(&argvars[2]));
Bram Moolenaar9f9fe372019-07-27 23:12:12 +0200684 return;
685 }
Bram Moolenaar9f9fe372019-07-27 23:12:12 +0200686 }
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000687 val = tv_get_number_chk(&argvars[1], &error);
688 if (error)
689 return;
690 if (val < 0 || val > 255)
691 {
Bram Moolenaar436b5ad2021-12-31 22:49:24 +0000692 semsg(_(e_invalid_argument_str), tv_get_string(&argvars[1]));
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000693 return;
694 }
695
696 if (ga_grow(&b->bv_ga, 1) == FAIL)
697 return;
698 p = (char_u *)b->bv_ga.ga_data;
699 mch_memmove(p + before + 1, p + before, (size_t)len - before);
700 *(p + before) = val;
701 ++b->bv_ga.ga_len;
702
703 copy_tv(&argvars[0], rettv);
704}
705
706/*
Bram Moolenaarf1c60d42022-09-22 17:07:00 +0100707 * Implementaion of reduce() for Blob "argvars[0]" using the function "expr"
708 * starting with the optional initial value "argvars[2]" and return the result
709 * in "rettv".
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000710 */
711 void
712blob_reduce(
713 typval_T *argvars,
Bram Moolenaarf1c60d42022-09-22 17:07:00 +0100714 typval_T *expr,
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000715 typval_T *rettv)
716{
717 blob_T *b = argvars[0].vval.v_blob;
718 int called_emsg_start = called_emsg;
719 int r;
720 typval_T initial;
721 typval_T argv[3];
722 int i;
723
724 if (argvars[2].v_type == VAR_UNKNOWN)
725 {
726 if (b == NULL || b->bv_ga.ga_len == 0)
727 {
Bram Moolenaar460ae5d2022-01-01 14:19:49 +0000728 semsg(_(e_reduce_of_an_empty_str_with_no_initial_value), "Blob");
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000729 return;
730 }
731 initial.v_type = VAR_NUMBER;
732 initial.vval.v_number = blob_get(b, 0);
733 i = 1;
734 }
Yegappan Lakshmanan8deb2b32022-09-02 15:15:27 +0100735 else if (check_for_number_arg(argvars, 2) == FAIL)
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000736 return;
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000737 else
738 {
739 initial = argvars[2];
740 i = 0;
741 }
742
743 copy_tv(&initial, rettv);
744 if (b == NULL)
745 return;
746
747 for ( ; i < b->bv_ga.ga_len; i++)
748 {
749 argv[0] = *rettv;
750 argv[1].v_type = VAR_NUMBER;
751 argv[1].vval.v_number = blob_get(b, i);
Bram Moolenaarf1c60d42022-09-22 17:07:00 +0100752
Bram Moolenaar82418262022-09-28 16:16:15 +0100753 r = eval_expr_typval(expr, argv, 2, NULL, rettv);
Bram Moolenaarf1c60d42022-09-22 17:07:00 +0100754
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000755 clear_tv(&argv[0]);
756 if (r == FAIL || called_emsg != called_emsg_start)
757 return;
758 }
759}
760
761/*
762 * "reverse({blob})" function
763 */
764 void
765blob_reverse(blob_T *b, typval_T *rettv)
766{
767 int i, len = blob_len(b);
768
769 for (i = 0; i < len / 2; i++)
770 {
771 int tmp = blob_get(b, i);
772
773 blob_set(b, i, blob_get(b, len - i - 1));
774 blob_set(b, len - i - 1, tmp);
775 }
776 rettv_blob_set(rettv, b);
Bram Moolenaar9f9fe372019-07-27 23:12:12 +0200777}
778
Yegappan Lakshmanan5dfe4672021-09-14 17:54:30 +0200779/*
780 * blob2list() function
781 */
782 void
783f_blob2list(typval_T *argvars, typval_T *rettv)
784{
785 blob_T *blob;
786 list_T *l;
787 int i;
788
789 if (rettv_list_alloc(rettv) == FAIL)
790 return;
791
792 if (check_for_blob_arg(argvars, 0) == FAIL)
793 return;
794
795 blob = argvars->vval.v_blob;
796 l = rettv->vval.v_list;
797 for (i = 0; i < blob_len(blob); i++)
798 list_append_number(l, blob_get(blob, i));
799}
800
801/*
802 * list2blob() function
803 */
804 void
805f_list2blob(typval_T *argvars, typval_T *rettv)
806{
807 list_T *l;
808 listitem_T *li;
809 blob_T *blob;
810
811 if (rettv_blob_alloc(rettv) == FAIL)
812 return;
813 blob = rettv->vval.v_blob;
814
815 if (check_for_list_arg(argvars, 0) == FAIL)
816 return;
817
818 l = argvars->vval.v_list;
819 if (l == NULL)
820 return;
821
kuuote04b7b4b2021-12-03 13:57:00 +0000822 CHECK_LIST_MATERIALIZE(l);
Yegappan Lakshmanan5dfe4672021-09-14 17:54:30 +0200823 FOR_ALL_LIST_ITEMS(l, li)
824 {
825 int error;
826 varnumber_T n;
827
828 error = FALSE;
829 n = tv_get_number_chk(&li->li_tv, &error);
830 if (error == TRUE || n < 0 || n > 255)
831 {
832 if (!error)
833 semsg(_(e_invalid_value_for_blob_nr), n);
834 ga_clear(&blob->bv_ga);
835 return;
836 }
837 ga_append(&blob->bv_ga, n);
838 }
839}
840
Bram Moolenaarc667da52019-11-30 20:52:27 +0100841#endif // defined(FEAT_EVAL)