blob: c5d7eaed64721ffa405153d6af6e23f773fe5c1f [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 {
Bram Moolenaar5b2a3d72022-10-21 11:25:30 +0100202 // The size defaults to the whole file. If a size is given it is
203 // limited to not go past the end of the file.
204 if (size == -1 || (size > st.st_size - offset
205#ifdef S_ISCHR
206 && !S_ISCHR(st.st_mode)
207#endif
208 ))
K.Takata11df3ae2022-10-19 14:02:40 +0100209 // size may become negative, checked below
210 size = st.st_size - offset;
211 whence = SEEK_SET;
212 }
213 else
214 {
Bram Moolenaar5b2a3d72022-10-21 11:25:30 +0100215 // limit the offset to not go before the start of the file
216 if (-offset > st.st_size
217#ifdef S_ISCHR
218 && !S_ISCHR(st.st_mode)
219#endif
220 )
221 offset = -st.st_size;
222 // Size defaults to reading until the end of the file.
223 if (size == -1 || size > -offset)
K.Takata11df3ae2022-10-19 14:02:40 +0100224 size = -offset;
225 whence = SEEK_END;
226 }
Bram Moolenaar5b2a3d72022-10-21 11:25:30 +0100227 if (size <= 0)
K.Takata11df3ae2022-10-19 14:02:40 +0100228 return OK;
K.Takata43625762022-10-20 13:28:51 +0100229 if (offset != 0 && vim_fseek(fd, offset, whence) != 0)
K.Takata11df3ae2022-10-19 14:02:40 +0100230 return OK;
231
232 if (ga_grow(&blob->bv_ga, (int)size) == FAIL)
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +0100233 return FAIL;
K.Takata11df3ae2022-10-19 14:02:40 +0100234 blob->bv_ga.ga_len = (int)size;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +0100235 if (fread(blob->bv_ga.ga_data, 1, blob->bv_ga.ga_len, fd)
236 < (size_t)blob->bv_ga.ga_len)
K.Takata11df3ae2022-10-19 14:02:40 +0100237 {
238 // An empty blob is returned on error.
239 blob_free(rettv->vval.v_blob);
240 rettv->vval.v_blob = NULL;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +0100241 return FAIL;
K.Takata11df3ae2022-10-19 14:02:40 +0100242 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +0100243 return OK;
244}
245
246/*
247 * Write "blob" to file "fd".
248 * Return OK or FAIL.
249 */
250 int
251write_blob(FILE *fd, blob_T *blob)
252{
253 if (fwrite(blob->bv_ga.ga_data, 1, blob->bv_ga.ga_len, fd)
254 < (size_t)blob->bv_ga.ga_len)
255 {
Bram Moolenaar40bcec12021-12-05 22:19:27 +0000256 emsg(_(e_error_while_writing));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +0100257 return FAIL;
258 }
259 return OK;
260}
261
Bram Moolenaar8c8b8bb2019-01-13 17:48:04 +0100262/*
Bram Moolenaar4131fd52019-01-17 16:32:53 +0100263 * Convert a blob to a readable form: "0z00112233.44556677.8899"
Bram Moolenaar8c8b8bb2019-01-13 17:48:04 +0100264 */
265 char_u *
266blob2string(blob_T *blob, char_u **tofree, char_u *numbuf)
267{
268 int i;
269 garray_T ga;
270
271 if (blob == NULL)
272 {
273 *tofree = NULL;
Bram Moolenaar4131fd52019-01-17 16:32:53 +0100274 return (char_u *)"0z";
Bram Moolenaar8c8b8bb2019-01-13 17:48:04 +0100275 }
276
277 // Store bytes in the growarray.
278 ga_init2(&ga, 1, 4000);
Bram Moolenaar4131fd52019-01-17 16:32:53 +0100279 ga_concat(&ga, (char_u *)"0z");
Bram Moolenaar8c8b8bb2019-01-13 17:48:04 +0100280 for (i = 0; i < blob_len(blob); i++)
281 {
Bram Moolenaar4131fd52019-01-17 16:32:53 +0100282 if (i > 0 && (i & 3) == 0)
283 ga_concat(&ga, (char_u *)".");
=?UTF-8?q?Dundar=20G=C3=B6c?=420fabc2022-01-28 15:28:04 +0000284 vim_snprintf((char *)numbuf, NUMBUFLEN, "%02X", blob_get(blob, i));
Bram Moolenaar8c8b8bb2019-01-13 17:48:04 +0100285 ga_concat(&ga, numbuf);
286 }
Yegappan Lakshmananbc404bf2021-12-19 19:19:31 +0000287 ga_append(&ga, NUL); // append a NUL at the end
Bram Moolenaar8c8b8bb2019-01-13 17:48:04 +0100288 *tofree = ga.ga_data;
289 return *tofree;
290}
291
292/*
293 * Convert a string variable, in the format of blob2string(), to a blob.
294 * Return NULL when conversion failed.
295 */
296 blob_T *
297string2blob(char_u *str)
298{
299 blob_T *blob = blob_alloc();
300 char_u *s = str;
301
Bram Moolenaare142a942019-03-19 23:03:27 +0100302 if (blob == NULL)
303 return NULL;
Bram Moolenaar4131fd52019-01-17 16:32:53 +0100304 if (s[0] != '0' || (s[1] != 'z' && s[1] != 'Z'))
Bram Moolenaar8c8b8bb2019-01-13 17:48:04 +0100305 goto failed;
Bram Moolenaar4131fd52019-01-17 16:32:53 +0100306 s += 2;
307 while (vim_isxdigit(*s))
Bram Moolenaar8c8b8bb2019-01-13 17:48:04 +0100308 {
Bram Moolenaar4131fd52019-01-17 16:32:53 +0100309 if (!vim_isxdigit(s[1]))
Bram Moolenaar8c8b8bb2019-01-13 17:48:04 +0100310 goto failed;
Bram Moolenaar4131fd52019-01-17 16:32:53 +0100311 ga_append(&blob->bv_ga, (hex2nr(s[0]) << 4) + hex2nr(s[1]));
312 s += 2;
313 if (*s == '.' && vim_isxdigit(s[1]))
314 ++s;
Bram Moolenaar8c8b8bb2019-01-13 17:48:04 +0100315 }
Bram Moolenaar4131fd52019-01-17 16:32:53 +0100316 if (*skipwhite(s) != NUL)
317 goto failed; // text after final digit
Bram Moolenaar8c8b8bb2019-01-13 17:48:04 +0100318
319 ++blob->bv_refcount;
320 return blob;
321
322failed:
323 blob_free(blob);
324 return NULL;
325}
326
Yegappan Lakshmanan368aa692022-09-27 11:46:48 +0100327/*
328 * Returns a slice of 'blob' from index 'n1' to 'n2' in 'rettv'. The length of
329 * the blob is 'len'. Returns an empty blob if the indexes are out of range.
330 */
331 static int
332blob_slice(
333 blob_T *blob,
334 long len,
335 varnumber_T n1,
336 varnumber_T n2,
337 int exclusive,
338 typval_T *rettv)
339{
340 if (n1 < 0)
341 {
342 n1 = len + n1;
343 if (n1 < 0)
344 n1 = 0;
345 }
346 if (n2 < 0)
347 n2 = len + n2;
348 else if (n2 >= len)
349 n2 = len - (exclusive ? 0 : 1);
350 if (exclusive)
351 --n2;
352 if (n1 >= len || n2 < 0 || n1 > n2)
353 {
354 clear_tv(rettv);
355 rettv->v_type = VAR_BLOB;
356 rettv->vval.v_blob = NULL;
357 }
358 else
359 {
360 blob_T *new_blob = blob_alloc();
361 long i;
362
363 if (new_blob != NULL)
364 {
365 if (ga_grow(&new_blob->bv_ga, n2 - n1 + 1) == FAIL)
366 {
367 blob_free(new_blob);
368 return FAIL;
369 }
370 new_blob->bv_ga.ga_len = n2 - n1 + 1;
371 for (i = n1; i <= n2; i++)
372 blob_set(new_blob, i - n1, blob_get(blob, i));
373
374 clear_tv(rettv);
375 rettv_blob_set(rettv, new_blob);
376 }
377 }
378
379 return OK;
380}
381
382/*
383 * Return the byte value in 'blob' at index 'idx' in 'rettv'. If the index is
384 * too big or negative that is an error. The length of the blob is 'len'.
385 */
386 static int
387blob_index(
388 blob_T *blob,
389 int len,
390 varnumber_T idx,
391 typval_T *rettv)
392{
393 // The resulting variable is a byte value.
394 // If the index is too big or negative that is an error.
395 if (idx < 0)
396 idx = len + idx;
397 if (idx < len && idx >= 0)
398 {
399 int v = blob_get(blob, idx);
400
401 clear_tv(rettv);
402 rettv->v_type = VAR_NUMBER;
403 rettv->vval.v_number = v;
404 }
405 else
406 {
407 semsg(_(e_blob_index_out_of_range_nr), idx);
408 return FAIL;
409 }
410
411 return OK;
412}
413
Bram Moolenaarcfc30232021-04-11 20:26:34 +0200414 int
415blob_slice_or_index(
416 blob_T *blob,
417 int is_range,
418 varnumber_T n1,
419 varnumber_T n2,
420 int exclusive,
421 typval_T *rettv)
422{
Yegappan Lakshmanan368aa692022-09-27 11:46:48 +0100423 long len = blob_len(blob);
Bram Moolenaarcfc30232021-04-11 20:26:34 +0200424
425 if (is_range)
Yegappan Lakshmanan368aa692022-09-27 11:46:48 +0100426 return blob_slice(blob, len, n1, n2, exclusive, rettv);
Bram Moolenaarcfc30232021-04-11 20:26:34 +0200427 else
Yegappan Lakshmanan368aa692022-09-27 11:46:48 +0100428 return blob_index(blob, len, n1, rettv);
Bram Moolenaarcfc30232021-04-11 20:26:34 +0200429 return OK;
430}
431
Bram Moolenaar9f9fe372019-07-27 23:12:12 +0200432/*
Bram Moolenaar0e3ff192021-04-14 20:35:23 +0200433 * Check if "n1"- is a valid index for a blobl with length "bloblen".
434 */
435 int
Bram Moolenaarbd6406f2021-04-14 21:30:06 +0200436check_blob_index(long bloblen, varnumber_T n1, int quiet)
Bram Moolenaar0e3ff192021-04-14 20:35:23 +0200437{
438 if (n1 < 0 || n1 > bloblen)
439 {
440 if (!quiet)
Bram Moolenaar460ae5d2022-01-01 14:19:49 +0000441 semsg(_(e_blob_index_out_of_range_nr), n1);
Bram Moolenaar0e3ff192021-04-14 20:35:23 +0200442 return FAIL;
443 }
444 return OK;
445}
446
447/*
448 * Check if "n1"-"n2" is a valid range for a blob with length "bloblen".
449 */
450 int
451check_blob_range(long bloblen, varnumber_T n1, varnumber_T n2, int quiet)
452{
453 if (n2 < 0 || n2 >= bloblen || n2 < n1)
454 {
455 if (!quiet)
Bram Moolenaar460ae5d2022-01-01 14:19:49 +0000456 semsg(_(e_blob_index_out_of_range_nr), n2);
Bram Moolenaar0e3ff192021-04-14 20:35:23 +0200457 return FAIL;
458 }
459 return OK;
460}
461
462/*
Bram Moolenaar68452172021-04-12 21:21:02 +0200463 * Set bytes "n1" to "n2" (inclusive) in "dest" to the value of "src".
464 * Caller must make sure "src" is a blob.
465 * Returns FAIL if the number of bytes does not match.
466 */
467 int
468blob_set_range(blob_T *dest, long n1, long n2, typval_T *src)
469{
470 int il, ir;
471
472 if (n2 - n1 + 1 != blob_len(src->vval.v_blob))
473 {
Bram Moolenaarf1474d82021-12-31 19:59:55 +0000474 emsg(_(e_blob_value_does_not_have_right_number_of_bytes));
Bram Moolenaar68452172021-04-12 21:21:02 +0200475 return FAIL;
476 }
477
478 ir = 0;
479 for (il = n1; il <= n2; il++)
480 blob_set(dest, il, blob_get(src->vval.v_blob, ir++));
481 return OK;
482}
483
484/*
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000485 * "add(blob, item)" function
486 */
487 void
488blob_add(typval_T *argvars, typval_T *rettv)
489{
490 blob_T *b = argvars[0].vval.v_blob;
491 int error = FALSE;
492 varnumber_T n;
493
494 if (b == NULL)
495 {
496 if (in_vim9script())
497 emsg(_(e_cannot_add_to_null_blob));
498 return;
499 }
500
501 if (value_check_lock(b->bv_lock, (char_u *)N_("add() argument"), TRUE))
502 return;
503
504 n = tv_get_number_chk(&argvars[1], &error);
505 if (error)
506 return;
507
508 ga_append(&b->bv_ga, (int)n);
509 copy_tv(&argvars[0], rettv);
510}
511
512/*
513 * "remove({blob}, {idx} [, {end}])" function
Bram Moolenaar9f9fe372019-07-27 23:12:12 +0200514 */
515 void
Sean Dewar80d73952021-08-04 19:25:54 +0200516blob_remove(typval_T *argvars, typval_T *rettv, char_u *arg_errmsg)
Bram Moolenaar9f9fe372019-07-27 23:12:12 +0200517{
Sean Dewar80d73952021-08-04 19:25:54 +0200518 blob_T *b = argvars[0].vval.v_blob;
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000519 blob_T *newblob;
Bram Moolenaar9f9fe372019-07-27 23:12:12 +0200520 int error = FALSE;
Yegappan Lakshmanan83494b42021-07-20 17:51:51 +0200521 long idx;
Bram Moolenaar9f9fe372019-07-27 23:12:12 +0200522 long end;
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000523 int len;
524 char_u *p;
Bram Moolenaar9f9fe372019-07-27 23:12:12 +0200525
Sean Dewar80d73952021-08-04 19:25:54 +0200526 if (b != NULL && value_check_lock(b->bv_lock, arg_errmsg, TRUE))
527 return;
528
Yegappan Lakshmanan83494b42021-07-20 17:51:51 +0200529 idx = (long)tv_get_number_chk(&argvars[1], &error);
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000530 if (error)
531 return;
Bram Moolenaar9f9fe372019-07-27 23:12:12 +0200532
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000533 len = blob_len(b);
534
535 if (idx < 0)
536 // count from the end
537 idx = len + idx;
538 if (idx < 0 || idx >= len)
539 {
Bram Moolenaar460ae5d2022-01-01 14:19:49 +0000540 semsg(_(e_blob_index_out_of_range_nr), idx);
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000541 return;
542 }
543 if (argvars[2].v_type == VAR_UNKNOWN)
544 {
545 // Remove one item, return its value.
546 p = (char_u *)b->bv_ga.ga_data;
547 rettv->vval.v_number = (varnumber_T) *(p + idx);
548 mch_memmove(p + idx, p + idx + 1, (size_t)len - idx - 1);
549 --b->bv_ga.ga_len;
550 return;
551 }
552
553 // Remove range of items, return blob with values.
554 end = (long)tv_get_number_chk(&argvars[2], &error);
555 if (error)
556 return;
557 if (end < 0)
558 // count from the end
559 end = len + end;
560 if (end >= len || idx > end)
561 {
Bram Moolenaar460ae5d2022-01-01 14:19:49 +0000562 semsg(_(e_blob_index_out_of_range_nr), end);
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000563 return;
564 }
565 newblob = blob_alloc();
566 if (newblob == NULL)
567 return;
568 newblob->bv_ga.ga_len = end - idx + 1;
569 if (ga_grow(&newblob->bv_ga, end - idx + 1) == FAIL)
570 {
571 vim_free(newblob);
572 return;
573 }
574 p = (char_u *)b->bv_ga.ga_data;
575 mch_memmove((char_u *)newblob->bv_ga.ga_data, p + idx,
576 (size_t)(end - idx + 1));
577 ++newblob->bv_refcount;
578 rettv->v_type = VAR_BLOB;
579 rettv->vval.v_blob = newblob;
580
581 if (len - end - 1 > 0)
582 mch_memmove(p + idx, p + end + 1, (size_t)(len - end - 1));
583 b->bv_ga.ga_len -= end - idx + 1;
584}
585
586/*
587 * Implementation of map() and filter() for a Blob. Apply "expr" to every
588 * number in Blob "blob_arg" and return the result in "rettv".
589 */
590 void
591blob_filter_map(
592 blob_T *blob_arg,
593 filtermap_T filtermap,
594 typval_T *expr,
Ernie Raele6d40dc2023-03-19 21:23:38 +0000595 char_u *arg_errmsg,
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000596 typval_T *rettv)
597{
Ernie Raele6d40dc2023-03-19 21:23:38 +0000598 blob_T *b = blob_arg;
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000599 int i;
600 typval_T tv;
601 varnumber_T val;
602 blob_T *b_ret;
603 int idx = 0;
604 int rem;
Bram Moolenaar82418262022-09-28 16:16:15 +0100605 typval_T newtv;
606 funccall_T *fc;
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000607
608 if (filtermap == FILTERMAP_MAPNEW)
609 {
610 rettv->v_type = VAR_BLOB;
611 rettv->vval.v_blob = NULL;
612 }
Ernie Raele6d40dc2023-03-19 21:23:38 +0000613 if (b == NULL || (filtermap == FILTERMAP_FILTER
614 && value_check_lock(b->bv_lock, arg_errmsg, TRUE)))
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000615 return;
616
617 b_ret = b;
618 if (filtermap == FILTERMAP_MAPNEW)
619 {
620 if (blob_copy(b, rettv) == FAIL)
621 return;
622 b_ret = rettv->vval.v_blob;
623 }
624
625 // set_vim_var_nr() doesn't set the type
626 set_vim_var_type(VV_KEY, VAR_NUMBER);
627
Ernie Raele6d40dc2023-03-19 21:23:38 +0000628 int prev_lock = b->bv_lock;
629 if (b->bv_lock == 0)
630 b->bv_lock = VAR_LOCKED;
631
zeertzjqe7d49462023-04-16 20:53:55 +0100632 // Create one funccall_T for all eval_expr_typval() calls.
Bram Moolenaar82418262022-09-28 16:16:15 +0100633 fc = eval_expr_get_funccal(expr, &newtv);
634
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000635 for (i = 0; i < b->bv_ga.ga_len; i++)
636 {
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000637 tv.v_type = VAR_NUMBER;
638 val = blob_get(b, i);
639 tv.vval.v_number = val;
640 set_vim_var_nr(VV_KEY, idx);
Bram Moolenaar82418262022-09-28 16:16:15 +0100641 if (filter_map_one(&tv, expr, filtermap, fc, &newtv, &rem) == FAIL
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000642 || did_emsg)
643 break;
644 if (newtv.v_type != VAR_NUMBER && newtv.v_type != VAR_BOOL)
Bram Moolenaar9f9fe372019-07-27 23:12:12 +0200645 {
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000646 clear_tv(&newtv);
Bram Moolenaar460ae5d2022-01-01 14:19:49 +0000647 emsg(_(e_invalid_operation_for_blob));
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000648 break;
649 }
650 if (filtermap != FILTERMAP_FILTER)
651 {
652 if (newtv.vval.v_number != val)
653 blob_set(b_ret, i, newtv.vval.v_number);
654 }
655 else if (rem)
656 {
657 char_u *p = (char_u *)blob_arg->bv_ga.ga_data;
658
659 mch_memmove(p + i, p + i + 1,
660 (size_t)b->bv_ga.ga_len - i - 1);
661 --b->bv_ga.ga_len;
662 --i;
663 }
664 ++idx;
665 }
Bram Moolenaar82418262022-09-28 16:16:15 +0100666
Ernie Raele6d40dc2023-03-19 21:23:38 +0000667 b->bv_lock = prev_lock;
Bram Moolenaar82418262022-09-28 16:16:15 +0100668 if (fc != NULL)
669 remove_funccal();
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000670}
671
672/*
673 * "insert(blob, {item} [, {idx}])" function
674 */
675 void
676blob_insert_func(typval_T *argvars, typval_T *rettv)
677{
678 blob_T *b = argvars[0].vval.v_blob;
679 long before = 0;
680 int error = FALSE;
681 int val, len;
682 char_u *p;
683
684 if (b == NULL)
685 {
686 if (in_vim9script())
687 emsg(_(e_cannot_add_to_null_blob));
688 return;
689 }
690
691 if (value_check_lock(b->bv_lock, (char_u *)N_("insert() argument"), TRUE))
692 return;
693
694 len = blob_len(b);
695 if (argvars[2].v_type != VAR_UNKNOWN)
696 {
697 before = (long)tv_get_number_chk(&argvars[2], &error);
698 if (error)
699 return; // type error; errmsg already given
700 if (before < 0 || before > len)
701 {
Bram Moolenaar436b5ad2021-12-31 22:49:24 +0000702 semsg(_(e_invalid_argument_str), tv_get_string(&argvars[2]));
Bram Moolenaar9f9fe372019-07-27 23:12:12 +0200703 return;
704 }
Bram Moolenaar9f9fe372019-07-27 23:12:12 +0200705 }
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000706 val = tv_get_number_chk(&argvars[1], &error);
707 if (error)
708 return;
709 if (val < 0 || val > 255)
710 {
Bram Moolenaar436b5ad2021-12-31 22:49:24 +0000711 semsg(_(e_invalid_argument_str), tv_get_string(&argvars[1]));
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000712 return;
713 }
714
715 if (ga_grow(&b->bv_ga, 1) == FAIL)
716 return;
717 p = (char_u *)b->bv_ga.ga_data;
718 mch_memmove(p + before + 1, p + before, (size_t)len - before);
719 *(p + before) = val;
720 ++b->bv_ga.ga_len;
721
722 copy_tv(&argvars[0], rettv);
723}
724
725/*
dundargocc57b5bc2022-11-02 13:30:51 +0000726 * Implementation of reduce() for Blob "argvars[0]" using the function "expr"
Bram Moolenaarf1c60d42022-09-22 17:07:00 +0100727 * starting with the optional initial value "argvars[2]" and return the result
728 * in "rettv".
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000729 */
730 void
731blob_reduce(
732 typval_T *argvars,
Bram Moolenaarf1c60d42022-09-22 17:07:00 +0100733 typval_T *expr,
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000734 typval_T *rettv)
735{
736 blob_T *b = argvars[0].vval.v_blob;
737 int called_emsg_start = called_emsg;
738 int r;
739 typval_T initial;
740 typval_T argv[3];
741 int i;
742
743 if (argvars[2].v_type == VAR_UNKNOWN)
744 {
745 if (b == NULL || b->bv_ga.ga_len == 0)
746 {
Bram Moolenaar460ae5d2022-01-01 14:19:49 +0000747 semsg(_(e_reduce_of_an_empty_str_with_no_initial_value), "Blob");
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000748 return;
749 }
750 initial.v_type = VAR_NUMBER;
751 initial.vval.v_number = blob_get(b, 0);
752 i = 1;
753 }
Yegappan Lakshmanan8deb2b32022-09-02 15:15:27 +0100754 else if (check_for_number_arg(argvars, 2) == FAIL)
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000755 return;
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000756 else
757 {
758 initial = argvars[2];
759 i = 0;
760 }
761
762 copy_tv(&initial, rettv);
763 if (b == NULL)
764 return;
765
766 for ( ; i < b->bv_ga.ga_len; i++)
767 {
768 argv[0] = *rettv;
769 argv[1].v_type = VAR_NUMBER;
770 argv[1].vval.v_number = blob_get(b, i);
Bram Moolenaarf1c60d42022-09-22 17:07:00 +0100771
zeertzjqad0c4422023-08-17 22:15:47 +0200772 r = eval_expr_typval(expr, TRUE, argv, 2, NULL, rettv);
Bram Moolenaarf1c60d42022-09-22 17:07:00 +0100773
Yegappan Lakshmananf973eeb2021-12-22 18:19:26 +0000774 clear_tv(&argv[0]);
775 if (r == FAIL || called_emsg != called_emsg_start)
776 return;
777 }
778}
779
780/*
781 * "reverse({blob})" function
782 */
783 void
784blob_reverse(blob_T *b, typval_T *rettv)
785{
786 int i, len = blob_len(b);
787
788 for (i = 0; i < len / 2; i++)
789 {
790 int tmp = blob_get(b, i);
791
792 blob_set(b, i, blob_get(b, len - i - 1));
793 blob_set(b, len - i - 1, tmp);
794 }
795 rettv_blob_set(rettv, b);
Bram Moolenaar9f9fe372019-07-27 23:12:12 +0200796}
797
Yegappan Lakshmanan5dfe4672021-09-14 17:54:30 +0200798/*
799 * blob2list() function
800 */
801 void
802f_blob2list(typval_T *argvars, typval_T *rettv)
803{
804 blob_T *blob;
805 list_T *l;
806 int i;
807
808 if (rettv_list_alloc(rettv) == FAIL)
809 return;
810
811 if (check_for_blob_arg(argvars, 0) == FAIL)
812 return;
813
814 blob = argvars->vval.v_blob;
815 l = rettv->vval.v_list;
816 for (i = 0; i < blob_len(blob); i++)
817 list_append_number(l, blob_get(blob, i));
818}
819
820/*
821 * list2blob() function
822 */
823 void
824f_list2blob(typval_T *argvars, typval_T *rettv)
825{
826 list_T *l;
827 listitem_T *li;
828 blob_T *blob;
829
830 if (rettv_blob_alloc(rettv) == FAIL)
831 return;
832 blob = rettv->vval.v_blob;
833
834 if (check_for_list_arg(argvars, 0) == FAIL)
835 return;
836
837 l = argvars->vval.v_list;
838 if (l == NULL)
839 return;
840
kuuote04b7b4b2021-12-03 13:57:00 +0000841 CHECK_LIST_MATERIALIZE(l);
Yegappan Lakshmanan5dfe4672021-09-14 17:54:30 +0200842 FOR_ALL_LIST_ITEMS(l, li)
843 {
844 int error;
845 varnumber_T n;
846
847 error = FALSE;
848 n = tv_get_number_chk(&li->li_tv, &error);
849 if (error == TRUE || n < 0 || n > 255)
850 {
851 if (!error)
852 semsg(_(e_invalid_value_for_blob_nr), n);
853 ga_clear(&blob->bv_ga);
854 return;
855 }
856 ga_append(&blob->bv_ga, n);
857 }
858}
859
Bram Moolenaarc667da52019-11-30 20:52:27 +0100860#endif // defined(FEAT_EVAL)