]>
git.proxmox.com Git - libgit2.git/blob - src/buffer.c
2 * Copyright (C) the libgit2 contributors. All rights reserved.
4 * This file is part of libgit2, distributed under the GNU GPL v2 with
5 * a Linking Exception. For full terms see the included COPYING file.
9 #include "git2/buffer.h"
13 /* Used as default value for git_buf->ptr so that people can always
14 * assume ptr is non-NULL and zero terminated even for new git_bufs.
16 char git_buf__initbuf
[1];
20 #define ENSURE_SIZE(b, d) \
21 if ((d) > (b)->asize && git_buf_grow((b), (d)) < 0)\
25 int git_buf_init(git_buf
*buf
, size_t initial_size
)
29 buf
->ptr
= git_buf__initbuf
;
31 ENSURE_SIZE(buf
, initial_size
);
37 git_buf
*buf
, size_t target_size
, bool mark_oom
)
42 if (buf
->ptr
== git_buf__oom
)
45 if (buf
->asize
== 0 && buf
->size
!= 0) {
46 giterr_set(GITERR_INVALID
, "cannot grow a borrowed buffer");
51 target_size
= buf
->size
;
53 if (target_size
<= buf
->asize
)
56 if (buf
->asize
== 0) {
57 new_size
= target_size
;
60 new_size
= buf
->asize
;
64 /* grow the buffer size by 1.5, until it's big enough
65 * to fit our target size */
66 while (new_size
< target_size
)
67 new_size
= (new_size
<< 1) - (new_size
>> 1);
69 /* round allocation up to multiple of 8 */
70 new_size
= (new_size
+ 7) & ~7;
72 if (new_size
< buf
->size
) {
74 buf
->ptr
= git_buf__oom
;
80 new_ptr
= git__realloc(new_ptr
, new_size
);
84 if (buf
->ptr
&& (buf
->ptr
!= git_buf__initbuf
))
86 buf
->ptr
= git_buf__oom
;
91 buf
->asize
= new_size
;
94 /* truncate the existing buffer size if necessary */
95 if (buf
->size
>= buf
->asize
)
96 buf
->size
= buf
->asize
- 1;
97 buf
->ptr
[buf
->size
] = '\0';
102 int git_buf_grow(git_buf
*buffer
, size_t target_size
)
104 return git_buf_try_grow(buffer
, target_size
, true);
107 int git_buf_grow_by(git_buf
*buffer
, size_t additional_size
)
111 if (GIT_ADD_SIZET_OVERFLOW(&newsize
, buffer
->size
, additional_size
)) {
112 buffer
->ptr
= git_buf__oom
;
116 return git_buf_try_grow(buffer
, newsize
, true);
119 void git_buf_free(git_buf
*buf
)
123 if (buf
->asize
> 0 && buf
->ptr
!= NULL
&& buf
->ptr
!= git_buf__oom
)
126 git_buf_init(buf
, 0);
129 void git_buf_sanitize(git_buf
*buf
)
131 if (buf
->ptr
== NULL
) {
132 assert(buf
->size
== 0 && buf
->asize
== 0);
133 buf
->ptr
= git_buf__initbuf
;
134 } else if (buf
->asize
> buf
->size
)
135 buf
->ptr
[buf
->size
] = '\0';
138 void git_buf_clear(git_buf
*buf
)
143 buf
->ptr
= git_buf__initbuf
;
151 int git_buf_set(git_buf
*buf
, const void *data
, size_t len
)
155 if (len
== 0 || data
== NULL
) {
158 if (data
!= buf
->ptr
) {
159 GITERR_CHECK_ALLOC_ADD(&alloclen
, len
, 1);
160 ENSURE_SIZE(buf
, alloclen
);
161 memmove(buf
->ptr
, data
, len
);
165 if (buf
->asize
> buf
->size
)
166 buf
->ptr
[buf
->size
] = '\0';
172 int git_buf_is_binary(const git_buf
*buf
)
174 return git_buf_text_is_binary(buf
);
177 int git_buf_contains_nul(const git_buf
*buf
)
179 return git_buf_text_contains_nul(buf
);
182 int git_buf_sets(git_buf
*buf
, const char *string
)
184 return git_buf_set(buf
, string
, string
? strlen(string
) : 0);
187 int git_buf_putc(git_buf
*buf
, char c
)
190 GITERR_CHECK_ALLOC_ADD(&new_size
, buf
->size
, 2);
191 ENSURE_SIZE(buf
, new_size
);
192 buf
->ptr
[buf
->size
++] = c
;
193 buf
->ptr
[buf
->size
] = '\0';
197 int git_buf_putcn(git_buf
*buf
, char c
, size_t len
)
200 GITERR_CHECK_ALLOC_ADD(&new_size
, buf
->size
, len
);
201 GITERR_CHECK_ALLOC_ADD(&new_size
, new_size
, 1);
202 ENSURE_SIZE(buf
, new_size
);
203 memset(buf
->ptr
+ buf
->size
, c
, len
);
205 buf
->ptr
[buf
->size
] = '\0';
209 int git_buf_put(git_buf
*buf
, const char *data
, size_t len
)
216 GITERR_CHECK_ALLOC_ADD(&new_size
, buf
->size
, len
);
217 GITERR_CHECK_ALLOC_ADD(&new_size
, new_size
, 1);
218 ENSURE_SIZE(buf
, new_size
);
219 memmove(buf
->ptr
+ buf
->size
, data
, len
);
221 buf
->ptr
[buf
->size
] = '\0';
226 int git_buf_puts(git_buf
*buf
, const char *string
)
229 return git_buf_put(buf
, string
, strlen(string
));
232 static const char base64_encode
[] =
233 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
235 int git_buf_encode_base64(git_buf
*buf
, const char *data
, size_t len
)
237 size_t extra
= len
% 3;
238 uint8_t *write
, a
, b
, c
;
239 const uint8_t *read
= (const uint8_t *)data
;
240 size_t blocks
= (len
/ 3) + !!extra
, alloclen
;
242 GITERR_CHECK_ALLOC_ADD(&blocks
, blocks
, 1);
243 GITERR_CHECK_ALLOC_MULTIPLY(&alloclen
, blocks
, 4);
244 GITERR_CHECK_ALLOC_ADD(&alloclen
, alloclen
, buf
->size
);
246 ENSURE_SIZE(buf
, alloclen
);
247 write
= (uint8_t *)&buf
->ptr
[buf
->size
];
249 /* convert each run of 3 bytes into 4 output bytes */
250 for (len
-= extra
; len
> 0; len
-= 3) {
255 *write
++ = base64_encode
[a
>> 2];
256 *write
++ = base64_encode
[(a
& 0x03) << 4 | b
>> 4];
257 *write
++ = base64_encode
[(b
& 0x0f) << 2 | c
>> 6];
258 *write
++ = base64_encode
[c
& 0x3f];
263 b
= (extra
> 1) ? *read
++ : 0;
265 *write
++ = base64_encode
[a
>> 2];
266 *write
++ = base64_encode
[(a
& 0x03) << 4 | b
>> 4];
267 *write
++ = (extra
> 1) ? base64_encode
[(b
& 0x0f) << 2] : '=';
271 buf
->size
= ((char *)write
) - buf
->ptr
;
272 buf
->ptr
[buf
->size
] = '\0';
277 /* The inverse of base64_encode */
278 static const int8_t base64_decode
[] = {
279 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
280 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
281 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
282 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, 0, -1, -1,
283 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
284 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
285 -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
286 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
287 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
288 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
289 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
290 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
291 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
292 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
293 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
294 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
297 int git_buf_decode_base64(git_buf
*buf
, const char *base64
, size_t len
)
301 size_t orig_size
= buf
->size
, new_size
;
304 giterr_set(GITERR_INVALID
, "invalid base64 input");
308 assert(len
% 4 == 0);
309 GITERR_CHECK_ALLOC_ADD(&new_size
, (len
/ 4 * 3), buf
->size
);
310 GITERR_CHECK_ALLOC_ADD(&new_size
, new_size
, 1);
311 ENSURE_SIZE(buf
, new_size
);
313 for (i
= 0; i
< len
; i
+= 4) {
314 if ((a
= base64_decode
[(unsigned char)base64
[i
]]) < 0 ||
315 (b
= base64_decode
[(unsigned char)base64
[i
+1]]) < 0 ||
316 (c
= base64_decode
[(unsigned char)base64
[i
+2]]) < 0 ||
317 (d
= base64_decode
[(unsigned char)base64
[i
+3]]) < 0) {
318 buf
->size
= orig_size
;
319 buf
->ptr
[buf
->size
] = '\0';
321 giterr_set(GITERR_INVALID
, "invalid base64 input");
325 buf
->ptr
[buf
->size
++] = ((a
<< 2) | (b
& 0x30) >> 4);
326 buf
->ptr
[buf
->size
++] = ((b
& 0x0f) << 4) | ((c
& 0x3c) >> 2);
327 buf
->ptr
[buf
->size
++] = (c
& 0x03) << 6 | (d
& 0x3f);
330 buf
->ptr
[buf
->size
] = '\0';
334 static const char base85_encode
[] =
335 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!#$%&()*+-;<=>?@^_`{|}~";
337 int git_buf_encode_base85(git_buf
*buf
, const char *data
, size_t len
)
339 size_t blocks
= (len
/ 4) + !!(len
% 4), alloclen
;
341 GITERR_CHECK_ALLOC_MULTIPLY(&alloclen
, blocks
, 5);
342 GITERR_CHECK_ALLOC_ADD(&alloclen
, alloclen
, buf
->size
);
343 GITERR_CHECK_ALLOC_ADD(&alloclen
, alloclen
, 1);
345 ENSURE_SIZE(buf
, alloclen
);
352 for (i
= 24; i
>= 0; i
-= 8) {
353 uint8_t ch
= *data
++;
360 for (i
= 4; i
>= 0; i
--) {
364 b85
[i
] = base85_encode
[val
];
367 for (i
= 0; i
< 5; i
++)
368 buf
->ptr
[buf
->size
++] = b85
[i
];
371 buf
->ptr
[buf
->size
] = '\0';
376 /* The inverse of base85_encode */
377 static const int8_t base85_decode
[] = {
378 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
379 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
380 -1, 63, -1, 64, 65, 66, 67, -1, 68, 69, 70, 71, -1, 72, -1, -1,
381 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, -1, 73, 74, 75, 76, 77,
382 78, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
383 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, -1, -1, -1, 79, 80,
384 81, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,
385 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 82, 83, 84, 85, -1,
386 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
387 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
388 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
389 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
390 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
391 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
392 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
393 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
396 int git_buf_decode_base85(
402 size_t orig_size
= buf
->size
, new_size
;
404 if (base85_len
% 5 ||
405 output_len
> base85_len
* 4 / 5) {
406 giterr_set(GITERR_INVALID
, "invalid base85 input");
410 GITERR_CHECK_ALLOC_ADD(&new_size
, output_len
, buf
->size
);
411 GITERR_CHECK_ALLOC_ADD(&new_size
, new_size
, 1);
412 ENSURE_SIZE(buf
, new_size
);
420 de
= base85_decode
[ch
];
427 de
= base85_decode
[ch
];
431 /* Detect overflow. */
432 if (0xffffffff / 85 < acc
||
433 0xffffffff - de
< (acc
*= 85))
438 cnt
= (output_len
< 4) ? output_len
: 4;
441 acc
= (acc
<< 8) | (acc
>> 24);
442 buf
->ptr
[buf
->size
++] = acc
;
446 buf
->ptr
[buf
->size
] = 0;
451 buf
->size
= orig_size
;
452 buf
->ptr
[buf
->size
] = '\0';
454 giterr_set(GITERR_INVALID
, "invalid base85 input");
458 int git_buf_vprintf(git_buf
*buf
, const char *format
, va_list ap
)
460 size_t expected_size
, new_size
;
463 GITERR_CHECK_ALLOC_MULTIPLY(&expected_size
, strlen(format
), 2);
464 GITERR_CHECK_ALLOC_ADD(&expected_size
, expected_size
, buf
->size
);
465 ENSURE_SIZE(buf
, expected_size
);
472 buf
->ptr
+ buf
->size
,
473 buf
->asize
- buf
->size
,
481 buf
->ptr
= git_buf__oom
;
485 if ((size_t)len
+ 1 <= buf
->asize
- buf
->size
) {
490 GITERR_CHECK_ALLOC_ADD(&new_size
, buf
->size
, len
);
491 GITERR_CHECK_ALLOC_ADD(&new_size
, new_size
, 1);
492 ENSURE_SIZE(buf
, new_size
);
498 int git_buf_printf(git_buf
*buf
, const char *format
, ...)
503 va_start(ap
, format
);
504 r
= git_buf_vprintf(buf
, format
, ap
);
510 void git_buf_copy_cstr(char *data
, size_t datasize
, const git_buf
*buf
)
514 assert(data
&& datasize
&& buf
);
518 if (buf
->size
== 0 || buf
->asize
<= 0)
522 if (copylen
> datasize
- 1)
523 copylen
= datasize
- 1;
524 memmove(data
, buf
->ptr
, copylen
);
525 data
[copylen
] = '\0';
528 void git_buf_consume(git_buf
*buf
, const char *end
)
530 if (end
> buf
->ptr
&& end
<= buf
->ptr
+ buf
->size
) {
531 size_t consumed
= end
- buf
->ptr
;
532 memmove(buf
->ptr
, end
, buf
->size
- consumed
);
533 buf
->size
-= consumed
;
534 buf
->ptr
[buf
->size
] = '\0';
538 void git_buf_truncate(git_buf
*buf
, size_t len
)
540 if (len
>= buf
->size
)
544 if (buf
->size
< buf
->asize
)
545 buf
->ptr
[buf
->size
] = '\0';
548 void git_buf_shorten(git_buf
*buf
, size_t amount
)
550 if (buf
->size
> amount
)
551 git_buf_truncate(buf
, buf
->size
- amount
);
556 void git_buf_rtruncate_at_char(git_buf
*buf
, char separator
)
558 ssize_t idx
= git_buf_rfind_next(buf
, separator
);
559 git_buf_truncate(buf
, idx
< 0 ? 0 : (size_t)idx
);
562 void git_buf_swap(git_buf
*buf_a
, git_buf
*buf_b
)
569 char *git_buf_detach(git_buf
*buf
)
571 char *data
= buf
->ptr
;
573 if (buf
->asize
== 0 || buf
->ptr
== git_buf__oom
)
576 git_buf_init(buf
, 0);
581 int git_buf_attach(git_buf
*buf
, char *ptr
, size_t asize
)
587 buf
->size
= strlen(ptr
);
589 buf
->asize
= (asize
< buf
->size
) ? buf
->size
+ 1 : asize
;
590 else /* pass 0 to fall back on strlen + 1 */
591 buf
->asize
= buf
->size
+ 1;
594 ENSURE_SIZE(buf
, asize
);
598 void git_buf_attach_notowned(git_buf
*buf
, const char *ptr
, size_t size
)
600 if (git_buf_is_allocated(buf
))
604 git_buf_init(buf
, 0);
606 buf
->ptr
= (char *)ptr
;
612 int git_buf_join_n(git_buf
*buf
, char separator
, int nbuf
, ...)
616 size_t total_size
= 0, original_size
= buf
->size
;
617 char *out
, *original
= buf
->ptr
;
619 if (buf
->size
> 0 && buf
->ptr
[buf
->size
- 1] != separator
)
620 ++total_size
; /* space for initial separator */
622 /* Make two passes to avoid multiple reallocation */
625 for (i
= 0; i
< nbuf
; ++i
) {
629 segment
= va_arg(ap
, const char *);
633 segment_len
= strlen(segment
);
635 GITERR_CHECK_ALLOC_ADD(&total_size
, total_size
, segment_len
);
637 if (segment_len
== 0 || segment
[segment_len
- 1] != separator
)
638 GITERR_CHECK_ALLOC_ADD(&total_size
, total_size
, 1);
642 /* expand buffer if needed */
646 GITERR_CHECK_ALLOC_ADD(&total_size
, total_size
, 1);
647 if (git_buf_grow_by(buf
, total_size
) < 0)
650 out
= buf
->ptr
+ buf
->size
;
652 /* append separator to existing buf if needed */
653 if (buf
->size
> 0 && out
[-1] != separator
)
657 for (i
= 0; i
< nbuf
; ++i
) {
661 segment
= va_arg(ap
, const char *);
665 /* deal with join that references buffer's original content */
666 if (segment
>= original
&& segment
< original
+ original_size
) {
667 size_t offset
= (segment
- original
);
668 segment
= buf
->ptr
+ offset
;
669 segment_len
= original_size
- offset
;
671 segment_len
= strlen(segment
);
674 /* skip leading separators */
675 if (out
> buf
->ptr
&& out
[-1] == separator
)
676 while (segment_len
> 0 && *segment
== separator
) {
681 /* copy over next buffer */
682 if (segment_len
> 0) {
683 memmove(out
, segment
, segment_len
);
687 /* append trailing separator (except for last item) */
688 if (i
< nbuf
- 1 && out
> buf
->ptr
&& out
[-1] != separator
)
693 /* set size based on num characters actually written */
694 buf
->size
= out
- buf
->ptr
;
695 buf
->ptr
[buf
->size
] = '\0';
706 size_t strlen_a
= str_a
? strlen(str_a
) : 0;
707 size_t strlen_b
= strlen(str_b
);
710 ssize_t offset_a
= -1;
712 /* not safe to have str_b point internally to the buffer */
713 assert(str_b
< buf
->ptr
|| str_b
>= buf
->ptr
+ buf
->size
);
715 /* figure out if we need to insert a separator */
716 if (separator
&& strlen_a
) {
717 while (*str_b
== separator
) { str_b
++; strlen_b
--; }
718 if (str_a
[strlen_a
- 1] != separator
)
722 /* str_a could be part of the buffer */
723 if (str_a
>= buf
->ptr
&& str_a
< buf
->ptr
+ buf
->size
)
724 offset_a
= str_a
- buf
->ptr
;
726 GITERR_CHECK_ALLOC_ADD(&alloc_len
, strlen_a
, strlen_b
);
727 GITERR_CHECK_ALLOC_ADD(&alloc_len
, alloc_len
, need_sep
);
728 GITERR_CHECK_ALLOC_ADD(&alloc_len
, alloc_len
, 1);
729 ENSURE_SIZE(buf
, alloc_len
);
731 /* fix up internal pointers */
733 str_a
= buf
->ptr
+ offset_a
;
735 /* do the actual copying */
736 if (offset_a
!= 0 && str_a
)
737 memmove(buf
->ptr
, str_a
, strlen_a
);
739 buf
->ptr
[strlen_a
] = separator
;
740 memcpy(buf
->ptr
+ strlen_a
+ need_sep
, str_b
, strlen_b
);
742 buf
->size
= strlen_a
+ strlen_b
+ need_sep
;
743 buf
->ptr
[buf
->size
] = '\0';
755 size_t len_a
= strlen(str_a
),
756 len_b
= strlen(str_b
),
757 len_c
= strlen(str_c
),
759 int sep_a
= 0, sep_b
= 0;
762 /* for this function, disallow pointers into the existing buffer */
763 assert(str_a
< buf
->ptr
|| str_a
>= buf
->ptr
+ buf
->size
);
764 assert(str_b
< buf
->ptr
|| str_b
>= buf
->ptr
+ buf
->size
);
765 assert(str_c
< buf
->ptr
|| str_c
>= buf
->ptr
+ buf
->size
);
769 while (*str_b
== separator
) { str_b
++; len_b
--; }
770 sep_a
= (str_a
[len_a
- 1] != separator
);
772 if (len_a
> 0 || len_b
> 0)
773 while (*str_c
== separator
) { str_c
++; len_c
--; }
775 sep_b
= (str_b
[len_b
- 1] != separator
);
778 GITERR_CHECK_ALLOC_ADD(&len_total
, len_a
, sep_a
);
779 GITERR_CHECK_ALLOC_ADD(&len_total
, len_total
, len_b
);
780 GITERR_CHECK_ALLOC_ADD(&len_total
, len_total
, sep_b
);
781 GITERR_CHECK_ALLOC_ADD(&len_total
, len_total
, len_c
);
782 GITERR_CHECK_ALLOC_ADD(&len_total
, len_total
, 1);
783 ENSURE_SIZE(buf
, len_total
);
788 memcpy(tgt
, str_a
, len_a
);
794 memcpy(tgt
, str_b
, len_b
);
800 memcpy(tgt
, str_c
, len_c
);
802 buf
->size
= len_a
+ sep_a
+ len_b
+ sep_b
+ len_c
;
803 buf
->ptr
[buf
->size
] = '\0';
808 void git_buf_rtrim(git_buf
*buf
)
810 while (buf
->size
> 0) {
811 if (!git__isspace(buf
->ptr
[buf
->size
- 1]))
817 if (buf
->asize
> buf
->size
)
818 buf
->ptr
[buf
->size
] = '\0';
821 int git_buf_cmp(const git_buf
*a
, const git_buf
*b
)
823 int result
= memcmp(a
->ptr
, b
->ptr
, min(a
->size
, b
->size
));
824 return (result
!= 0) ? result
:
825 (a
->size
< b
->size
) ? -1 : (a
->size
> b
->size
) ? 1 : 0;
836 size_t new_size
, alloc_size
;
838 assert(buf
&& where
<= buf
->size
&& nb_to_remove
<= buf
->size
- where
);
840 splice_loc
= buf
->ptr
+ where
;
842 /* Ported from git.git
843 * https://github.com/git/git/blob/16eed7c/strbuf.c#L159-176
845 GITERR_CHECK_ALLOC_ADD(&new_size
, (buf
->size
- nb_to_remove
), nb_to_insert
);
846 GITERR_CHECK_ALLOC_ADD(&alloc_size
, new_size
, 1);
847 ENSURE_SIZE(buf
, alloc_size
);
849 memmove(splice_loc
+ nb_to_insert
,
850 splice_loc
+ nb_to_remove
,
851 buf
->size
- where
- nb_to_remove
);
853 memcpy(splice_loc
, data
, nb_to_insert
);
855 buf
->size
= new_size
;
856 buf
->ptr
[buf
->size
] = '\0';
860 /* Quote per http://marc.info/?l=git&m=112927316408690&w=2 */
861 int git_buf_quote(git_buf
*buf
)
863 const char whitespace
[] = { 'a', 'b', 't', 'n', 'v', 'f', 'r' };
864 git_buf quoted
= GIT_BUF_INIT
;
869 /* walk to the first char that needs quoting */
870 if (buf
->size
&& buf
->ptr
[0] == '!')
873 for (i
= 0; !quote
&& i
< buf
->size
; i
++) {
874 if (buf
->ptr
[i
] == '"' || buf
->ptr
[i
] == '\\' ||
875 buf
->ptr
[i
] < ' ' || buf
->ptr
[i
] > '~') {
884 git_buf_putc("ed
, '"');
885 git_buf_put("ed
, buf
->ptr
, i
);
887 for (; i
< buf
->size
; i
++) {
888 /* whitespace - use the map above, which is ordered by ascii value */
889 if (buf
->ptr
[i
] >= '\a' && buf
->ptr
[i
] <= '\r') {
890 git_buf_putc("ed
, '\\');
891 git_buf_putc("ed
, whitespace
[buf
->ptr
[i
] - '\a']);
894 /* double quote and backslash must be escaped */
895 else if (buf
->ptr
[i
] == '"' || buf
->ptr
[i
] == '\\') {
896 git_buf_putc("ed
, '\\');
897 git_buf_putc("ed
, buf
->ptr
[i
]);
900 /* escape anything unprintable as octal */
901 else if (buf
->ptr
[i
] != ' ' &&
902 (buf
->ptr
[i
] < '!' || buf
->ptr
[i
] > '~')) {
903 git_buf_printf("ed
, "\\%03o", (unsigned char)buf
->ptr
[i
]);
906 /* yay, printable! */
908 git_buf_putc("ed
, buf
->ptr
[i
]);
912 git_buf_putc("ed
, '"');
914 if (git_buf_oom("ed
)) {
919 git_buf_swap("ed
, buf
);
922 git_buf_free("ed
);
926 /* Unquote per http://marc.info/?l=git&m=112927316408690&w=2 */
927 int git_buf_unquote(git_buf
*buf
)
934 if (buf
->size
< 2 || buf
->ptr
[0] != '"' || buf
->ptr
[buf
->size
-1] != '"')
937 for (i
= 0, j
= 1; j
< buf
->size
-1; i
++, j
++) {
941 if (j
== buf
->size
-2)
947 /* \" or \\ simply copy the char in */
951 /* add the appropriate escaped char */
952 case 'a': ch
= '\a'; break;
953 case 'b': ch
= '\b'; break;
954 case 'f': ch
= '\f'; break;
955 case 'n': ch
= '\n'; break;
956 case 'r': ch
= '\r'; break;
957 case 't': ch
= '\t'; break;
958 case 'v': ch
= '\v'; break;
960 /* \xyz digits convert to the char*/
961 case '0': case '1': case '2': case '3':
962 if (j
== buf
->size
-3) {
963 giterr_set(GITERR_INVALID
,
964 "truncated quoted character \\%c", ch
);
968 if (buf
->ptr
[j
+1] < '0' || buf
->ptr
[j
+1] > '7' ||
969 buf
->ptr
[j
+2] < '0' || buf
->ptr
[j
+2] > '7') {
970 giterr_set(GITERR_INVALID
,
971 "truncated quoted character \\%c%c%c",
972 buf
->ptr
[j
], buf
->ptr
[j
+1], buf
->ptr
[j
+2]);
976 ch
= ((buf
->ptr
[j
] - '0') << 6) |
977 ((buf
->ptr
[j
+1] - '0') << 3) |
978 (buf
->ptr
[j
+2] - '0');
983 giterr_set(GITERR_INVALID
, "invalid quoted character \\%c", ch
);
997 giterr_set(GITERR_INVALID
, "invalid quoted line");