]>
git.proxmox.com Git - libgit2.git/blob - src/buffer.c
31341c4b5d03fd7ce979642b1ff10ab5778b473c
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) > buf->asize && git_buf_grow(b, (d)) < 0)\
25 void git_buf_init(git_buf
*buf
, size_t initial_size
)
29 buf
->ptr
= git_buf__initbuf
;
32 git_buf_grow(buf
, initial_size
);
36 git_buf
*buf
, size_t target_size
, bool mark_oom
)
41 if (buf
->ptr
== git_buf__oom
)
44 if (buf
->asize
== 0 && buf
->size
!= 0) {
45 giterr_set(GITERR_INVALID
, "cannot grow a borrowed buffer");
50 target_size
= buf
->size
;
52 if (target_size
<= buf
->asize
)
55 if (buf
->asize
== 0) {
56 new_size
= target_size
;
59 new_size
= buf
->asize
;
63 /* grow the buffer size by 1.5, until it's big enough
64 * to fit our target size */
65 while (new_size
< target_size
)
66 new_size
= (new_size
<< 1) - (new_size
>> 1);
68 /* round allocation up to multiple of 8 */
69 new_size
= (new_size
+ 7) & ~7;
71 if (new_size
< buf
->size
) {
73 buf
->ptr
= git_buf__oom
;
79 new_ptr
= git__realloc(new_ptr
, new_size
);
83 if (buf
->ptr
&& (buf
->ptr
!= git_buf__initbuf
))
85 buf
->ptr
= git_buf__oom
;
90 buf
->asize
= new_size
;
93 /* truncate the existing buffer size if necessary */
94 if (buf
->size
>= buf
->asize
)
95 buf
->size
= buf
->asize
- 1;
96 buf
->ptr
[buf
->size
] = '\0';
101 int git_buf_grow(git_buf
*buffer
, size_t target_size
)
103 return git_buf_try_grow(buffer
, target_size
, true);
106 int git_buf_grow_by(git_buf
*buffer
, size_t additional_size
)
110 if (GIT_ADD_SIZET_OVERFLOW(&newsize
, buffer
->size
, additional_size
)) {
111 buffer
->ptr
= git_buf__oom
;
115 return git_buf_try_grow(buffer
, newsize
, true);
118 void git_buf_free(git_buf
*buf
)
122 if (buf
->asize
> 0 && buf
->ptr
!= NULL
&& buf
->ptr
!= git_buf__oom
)
125 git_buf_init(buf
, 0);
128 void git_buf_sanitize(git_buf
*buf
)
130 if (buf
->ptr
== NULL
) {
131 assert(buf
->size
== 0 && buf
->asize
== 0);
132 buf
->ptr
= git_buf__initbuf
;
133 } else if (buf
->asize
> buf
->size
)
134 buf
->ptr
[buf
->size
] = '\0';
137 void git_buf_clear(git_buf
*buf
)
142 buf
->ptr
= git_buf__initbuf
;
150 int git_buf_set(git_buf
*buf
, const void *data
, size_t len
)
154 if (len
== 0 || data
== NULL
) {
157 if (data
!= buf
->ptr
) {
158 GITERR_CHECK_ALLOC_ADD(&alloclen
, len
, 1);
159 ENSURE_SIZE(buf
, alloclen
);
160 memmove(buf
->ptr
, data
, len
);
164 if (buf
->asize
> buf
->size
)
165 buf
->ptr
[buf
->size
] = '\0';
171 int git_buf_is_binary(const git_buf
*buf
)
173 return git_buf_text_is_binary(buf
);
176 int git_buf_contains_nul(const git_buf
*buf
)
178 return git_buf_text_contains_nul(buf
);
181 int git_buf_sets(git_buf
*buf
, const char *string
)
183 return git_buf_set(buf
, string
, string
? strlen(string
) : 0);
186 int git_buf_putc(git_buf
*buf
, char c
)
189 GITERR_CHECK_ALLOC_ADD(&new_size
, buf
->size
, 2);
190 ENSURE_SIZE(buf
, new_size
);
191 buf
->ptr
[buf
->size
++] = c
;
192 buf
->ptr
[buf
->size
] = '\0';
196 int git_buf_putcn(git_buf
*buf
, char c
, size_t len
)
199 GITERR_CHECK_ALLOC_ADD(&new_size
, buf
->size
, len
);
200 GITERR_CHECK_ALLOC_ADD(&new_size
, new_size
, 1);
201 ENSURE_SIZE(buf
, new_size
);
202 memset(buf
->ptr
+ buf
->size
, c
, len
);
204 buf
->ptr
[buf
->size
] = '\0';
208 int git_buf_put(git_buf
*buf
, const char *data
, size_t len
)
215 GITERR_CHECK_ALLOC_ADD(&new_size
, buf
->size
, len
);
216 GITERR_CHECK_ALLOC_ADD(&new_size
, new_size
, 1);
217 ENSURE_SIZE(buf
, new_size
);
218 memmove(buf
->ptr
+ buf
->size
, data
, len
);
220 buf
->ptr
[buf
->size
] = '\0';
225 int git_buf_puts(git_buf
*buf
, const char *string
)
228 return git_buf_put(buf
, string
, strlen(string
));
231 static const char base64_encode
[] =
232 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
234 int git_buf_encode_base64(git_buf
*buf
, const char *data
, size_t len
)
236 size_t extra
= len
% 3;
237 uint8_t *write
, a
, b
, c
;
238 const uint8_t *read
= (const uint8_t *)data
;
239 size_t blocks
= (len
/ 3) + !!extra
, alloclen
;
241 GITERR_CHECK_ALLOC_ADD(&blocks
, blocks
, 1);
242 GITERR_CHECK_ALLOC_MULTIPLY(&alloclen
, blocks
, 4);
243 GITERR_CHECK_ALLOC_ADD(&alloclen
, alloclen
, buf
->size
);
245 ENSURE_SIZE(buf
, alloclen
);
246 write
= (uint8_t *)&buf
->ptr
[buf
->size
];
248 /* convert each run of 3 bytes into 4 output bytes */
249 for (len
-= extra
; len
> 0; len
-= 3) {
254 *write
++ = base64_encode
[a
>> 2];
255 *write
++ = base64_encode
[(a
& 0x03) << 4 | b
>> 4];
256 *write
++ = base64_encode
[(b
& 0x0f) << 2 | c
>> 6];
257 *write
++ = base64_encode
[c
& 0x3f];
262 b
= (extra
> 1) ? *read
++ : 0;
264 *write
++ = base64_encode
[a
>> 2];
265 *write
++ = base64_encode
[(a
& 0x03) << 4 | b
>> 4];
266 *write
++ = (extra
> 1) ? base64_encode
[(b
& 0x0f) << 2] : '=';
270 buf
->size
= ((char *)write
) - buf
->ptr
;
271 buf
->ptr
[buf
->size
] = '\0';
276 /* The inverse of base64_encode */
277 static const int8_t base64_decode
[] = {
278 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
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, 62, -1, -1, -1, 63,
281 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, 0, -1, -1,
282 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
283 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
284 -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
285 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
286 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -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
296 int git_buf_decode_base64(git_buf
*buf
, const char *base64
, size_t len
)
300 size_t orig_size
= buf
->size
, new_size
;
303 giterr_set(GITERR_INVALID
, "invalid base64 input");
307 assert(len
% 4 == 0);
308 GITERR_CHECK_ALLOC_ADD(&new_size
, (len
/ 4 * 3), buf
->size
);
309 GITERR_CHECK_ALLOC_ADD(&new_size
, new_size
, 1);
310 ENSURE_SIZE(buf
, new_size
);
312 for (i
= 0; i
< len
; i
+= 4) {
313 if ((a
= base64_decode
[(unsigned char)base64
[i
]]) < 0 ||
314 (b
= base64_decode
[(unsigned char)base64
[i
+1]]) < 0 ||
315 (c
= base64_decode
[(unsigned char)base64
[i
+2]]) < 0 ||
316 (d
= base64_decode
[(unsigned char)base64
[i
+3]]) < 0) {
317 buf
->size
= orig_size
;
318 buf
->ptr
[buf
->size
] = '\0';
320 giterr_set(GITERR_INVALID
, "invalid base64 input");
324 buf
->ptr
[buf
->size
++] = ((a
<< 2) | (b
& 0x30) >> 4);
325 buf
->ptr
[buf
->size
++] = ((b
& 0x0f) << 4) | ((c
& 0x3c) >> 2);
326 buf
->ptr
[buf
->size
++] = (c
& 0x03) << 6 | (d
& 0x3f);
329 buf
->ptr
[buf
->size
] = '\0';
333 static const char base85_encode
[] =
334 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!#$%&()*+-;<=>?@^_`{|}~";
336 int git_buf_encode_base85(git_buf
*buf
, const char *data
, size_t len
)
338 size_t blocks
= (len
/ 4) + !!(len
% 4), alloclen
;
340 GITERR_CHECK_ALLOC_MULTIPLY(&alloclen
, blocks
, 5);
341 GITERR_CHECK_ALLOC_ADD(&alloclen
, alloclen
, buf
->size
);
342 GITERR_CHECK_ALLOC_ADD(&alloclen
, alloclen
, 1);
344 ENSURE_SIZE(buf
, alloclen
);
351 for (i
= 24; i
>= 0; i
-= 8) {
352 uint8_t ch
= *data
++;
359 for (i
= 4; i
>= 0; i
--) {
363 b85
[i
] = base85_encode
[val
];
366 for (i
= 0; i
< 5; i
++)
367 buf
->ptr
[buf
->size
++] = b85
[i
];
370 buf
->ptr
[buf
->size
] = '\0';
375 /* The inverse of base85_encode */
376 static const int8_t base85_decode
[] = {
377 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
378 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
379 -1, 63, -1, 64, 65, 66, 67, -1, 68, 69, 70, 71, -1, 72, -1, -1,
380 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, -1, 73, 74, 75, 76, 77,
381 78, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
382 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, -1, -1, -1, 79, 80,
383 81, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,
384 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 82, 83, 84, 85, -1,
385 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -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
395 int git_buf_decode_base85(
401 size_t orig_size
= buf
->size
, new_size
;
403 if (base85_len
% 5 ||
404 output_len
> base85_len
* 4 / 5) {
405 giterr_set(GITERR_INVALID
, "invalid base85 input");
409 GITERR_CHECK_ALLOC_ADD(&new_size
, output_len
, buf
->size
);
410 GITERR_CHECK_ALLOC_ADD(&new_size
, new_size
, 1);
411 ENSURE_SIZE(buf
, new_size
);
419 de
= base85_decode
[ch
];
426 de
= base85_decode
[ch
];
430 /* Detect overflow. */
431 if (0xffffffff / 85 < acc
||
432 0xffffffff - de
< (acc
*= 85))
437 cnt
= (output_len
< 4) ? output_len
: 4;
440 acc
= (acc
<< 8) | (acc
>> 24);
441 buf
->ptr
[buf
->size
++] = acc
;
445 buf
->ptr
[buf
->size
] = 0;
450 buf
->size
= orig_size
;
451 buf
->ptr
[buf
->size
] = '\0';
453 giterr_set(GITERR_INVALID
, "invalid base85 input");
457 int git_buf_vprintf(git_buf
*buf
, const char *format
, va_list ap
)
459 size_t expected_size
, new_size
;
462 GITERR_CHECK_ALLOC_MULTIPLY(&expected_size
, strlen(format
), 2);
463 GITERR_CHECK_ALLOC_ADD(&expected_size
, expected_size
, buf
->size
);
464 ENSURE_SIZE(buf
, expected_size
);
471 buf
->ptr
+ buf
->size
,
472 buf
->asize
- buf
->size
,
480 buf
->ptr
= git_buf__oom
;
484 if ((size_t)len
+ 1 <= buf
->asize
- buf
->size
) {
489 GITERR_CHECK_ALLOC_ADD(&new_size
, buf
->size
, len
);
490 GITERR_CHECK_ALLOC_ADD(&new_size
, new_size
, 1);
491 ENSURE_SIZE(buf
, new_size
);
497 int git_buf_printf(git_buf
*buf
, const char *format
, ...)
502 va_start(ap
, format
);
503 r
= git_buf_vprintf(buf
, format
, ap
);
509 void git_buf_copy_cstr(char *data
, size_t datasize
, const git_buf
*buf
)
513 assert(data
&& datasize
&& buf
);
517 if (buf
->size
== 0 || buf
->asize
<= 0)
521 if (copylen
> datasize
- 1)
522 copylen
= datasize
- 1;
523 memmove(data
, buf
->ptr
, copylen
);
524 data
[copylen
] = '\0';
527 void git_buf_consume(git_buf
*buf
, const char *end
)
529 if (end
> buf
->ptr
&& end
<= buf
->ptr
+ buf
->size
) {
530 size_t consumed
= end
- buf
->ptr
;
531 memmove(buf
->ptr
, end
, buf
->size
- consumed
);
532 buf
->size
-= consumed
;
533 buf
->ptr
[buf
->size
] = '\0';
537 void git_buf_truncate(git_buf
*buf
, size_t len
)
539 if (len
>= buf
->size
)
543 if (buf
->size
< buf
->asize
)
544 buf
->ptr
[buf
->size
] = '\0';
547 void git_buf_shorten(git_buf
*buf
, size_t amount
)
549 if (buf
->size
> amount
)
550 git_buf_truncate(buf
, buf
->size
- amount
);
555 void git_buf_rtruncate_at_char(git_buf
*buf
, char separator
)
557 ssize_t idx
= git_buf_rfind_next(buf
, separator
);
558 git_buf_truncate(buf
, idx
< 0 ? 0 : (size_t)idx
);
561 void git_buf_swap(git_buf
*buf_a
, git_buf
*buf_b
)
568 char *git_buf_detach(git_buf
*buf
)
570 char *data
= buf
->ptr
;
572 if (buf
->asize
== 0 || buf
->ptr
== git_buf__oom
)
575 git_buf_init(buf
, 0);
580 void git_buf_attach(git_buf
*buf
, char *ptr
, size_t asize
)
586 buf
->size
= strlen(ptr
);
588 buf
->asize
= (asize
< buf
->size
) ? buf
->size
+ 1 : asize
;
589 else /* pass 0 to fall back on strlen + 1 */
590 buf
->asize
= buf
->size
+ 1;
592 git_buf_grow(buf
, asize
);
596 void git_buf_attach_notowned(git_buf
*buf
, const char *ptr
, size_t size
)
598 if (git_buf_is_allocated(buf
))
602 git_buf_init(buf
, 0);
604 buf
->ptr
= (char *)ptr
;
610 int git_buf_join_n(git_buf
*buf
, char separator
, int nbuf
, ...)
614 size_t total_size
= 0, original_size
= buf
->size
;
615 char *out
, *original
= buf
->ptr
;
617 if (buf
->size
> 0 && buf
->ptr
[buf
->size
- 1] != separator
)
618 ++total_size
; /* space for initial separator */
620 /* Make two passes to avoid multiple reallocation */
623 for (i
= 0; i
< nbuf
; ++i
) {
627 segment
= va_arg(ap
, const char *);
631 segment_len
= strlen(segment
);
633 GITERR_CHECK_ALLOC_ADD(&total_size
, total_size
, segment_len
);
635 if (segment_len
== 0 || segment
[segment_len
- 1] != separator
)
636 GITERR_CHECK_ALLOC_ADD(&total_size
, total_size
, 1);
640 /* expand buffer if needed */
644 GITERR_CHECK_ALLOC_ADD(&total_size
, total_size
, 1);
645 if (git_buf_grow_by(buf
, total_size
) < 0)
648 out
= buf
->ptr
+ buf
->size
;
650 /* append separator to existing buf if needed */
651 if (buf
->size
> 0 && out
[-1] != separator
)
655 for (i
= 0; i
< nbuf
; ++i
) {
659 segment
= va_arg(ap
, const char *);
663 /* deal with join that references buffer's original content */
664 if (segment
>= original
&& segment
< original
+ original_size
) {
665 size_t offset
= (segment
- original
);
666 segment
= buf
->ptr
+ offset
;
667 segment_len
= original_size
- offset
;
669 segment_len
= strlen(segment
);
672 /* skip leading separators */
673 if (out
> buf
->ptr
&& out
[-1] == separator
)
674 while (segment_len
> 0 && *segment
== separator
) {
679 /* copy over next buffer */
680 if (segment_len
> 0) {
681 memmove(out
, segment
, segment_len
);
685 /* append trailing separator (except for last item) */
686 if (i
< nbuf
- 1 && out
> buf
->ptr
&& out
[-1] != separator
)
691 /* set size based on num characters actually written */
692 buf
->size
= out
- buf
->ptr
;
693 buf
->ptr
[buf
->size
] = '\0';
704 size_t strlen_a
= str_a
? strlen(str_a
) : 0;
705 size_t strlen_b
= strlen(str_b
);
708 ssize_t offset_a
= -1;
710 /* not safe to have str_b point internally to the buffer */
711 assert(str_b
< buf
->ptr
|| str_b
>= buf
->ptr
+ buf
->size
);
713 /* figure out if we need to insert a separator */
714 if (separator
&& strlen_a
) {
715 while (*str_b
== separator
) { str_b
++; strlen_b
--; }
716 if (str_a
[strlen_a
- 1] != separator
)
720 /* str_a could be part of the buffer */
721 if (str_a
>= buf
->ptr
&& str_a
< buf
->ptr
+ buf
->size
)
722 offset_a
= str_a
- buf
->ptr
;
724 GITERR_CHECK_ALLOC_ADD(&alloc_len
, strlen_a
, strlen_b
);
725 GITERR_CHECK_ALLOC_ADD(&alloc_len
, alloc_len
, need_sep
);
726 GITERR_CHECK_ALLOC_ADD(&alloc_len
, alloc_len
, 1);
727 if (git_buf_grow(buf
, alloc_len
) < 0)
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 if (git_buf_grow(buf
, len_total
) < 0)
789 memcpy(tgt
, str_a
, len_a
);
795 memcpy(tgt
, str_b
, len_b
);
801 memcpy(tgt
, str_c
, len_c
);
803 buf
->size
= len_a
+ sep_a
+ len_b
+ sep_b
+ len_c
;
804 buf
->ptr
[buf
->size
] = '\0';
809 void git_buf_rtrim(git_buf
*buf
)
811 while (buf
->size
> 0) {
812 if (!git__isspace(buf
->ptr
[buf
->size
- 1]))
818 if (buf
->asize
> buf
->size
)
819 buf
->ptr
[buf
->size
] = '\0';
822 int git_buf_cmp(const git_buf
*a
, const git_buf
*b
)
824 int result
= memcmp(a
->ptr
, b
->ptr
, min(a
->size
, b
->size
));
825 return (result
!= 0) ? result
:
826 (a
->size
< b
->size
) ? -1 : (a
->size
> b
->size
) ? 1 : 0;
837 size_t new_size
, alloc_size
;
839 assert(buf
&& where
<= buf
->size
&& nb_to_remove
<= buf
->size
- where
);
841 splice_loc
= buf
->ptr
+ where
;
843 /* Ported from git.git
844 * https://github.com/git/git/blob/16eed7c/strbuf.c#L159-176
846 GITERR_CHECK_ALLOC_ADD(&new_size
, (buf
->size
- nb_to_remove
), nb_to_insert
);
847 GITERR_CHECK_ALLOC_ADD(&alloc_size
, new_size
, 1);
848 ENSURE_SIZE(buf
, alloc_size
);
850 memmove(splice_loc
+ nb_to_insert
,
851 splice_loc
+ nb_to_remove
,
852 buf
->size
- where
- nb_to_remove
);
854 memcpy(splice_loc
, data
, nb_to_insert
);
856 buf
->size
= new_size
;
857 buf
->ptr
[buf
->size
] = '\0';
861 /* Quote per http://marc.info/?l=git&m=112927316408690&w=2 */
862 int git_buf_quote(git_buf
*buf
)
864 const char whitespace
[] = { 'a', 'b', 't', 'n', 'v', 'f', 'r' };
865 git_buf quoted
= GIT_BUF_INIT
;
870 /* walk to the first char that needs quoting */
871 if (buf
->size
&& buf
->ptr
[0] == '!')
874 for (i
= 0; !quote
&& i
< buf
->size
; i
++) {
875 if (buf
->ptr
[i
] == '"' || buf
->ptr
[i
] == '\\' ||
876 buf
->ptr
[i
] < ' ' || buf
->ptr
[i
] > '~') {
885 git_buf_putc("ed
, '"');
886 git_buf_put("ed
, buf
->ptr
, i
);
888 for (; i
< buf
->size
; i
++) {
889 /* whitespace - use the map above, which is ordered by ascii value */
890 if (buf
->ptr
[i
] >= '\a' && buf
->ptr
[i
] <= '\r') {
891 git_buf_putc("ed
, '\\');
892 git_buf_putc("ed
, whitespace
[buf
->ptr
[i
] - '\a']);
895 /* double quote and backslash must be escaped */
896 else if (buf
->ptr
[i
] == '"' || buf
->ptr
[i
] == '\\') {
897 git_buf_putc("ed
, '\\');
898 git_buf_putc("ed
, buf
->ptr
[i
]);
901 /* escape anything unprintable as octal */
902 else if (buf
->ptr
[i
] != ' ' &&
903 (buf
->ptr
[i
] < '!' || buf
->ptr
[i
] > '~')) {
904 git_buf_printf("ed
, "\\%03o", buf
->ptr
[i
]);
907 /* yay, printable! */
909 git_buf_putc("ed
, buf
->ptr
[i
]);
913 git_buf_putc("ed
, '"');
915 if (git_buf_oom("ed
)) {
920 git_buf_swap("ed
, buf
);
923 git_buf_free("ed
);
927 /* Unquote per http://marc.info/?l=git&m=112927316408690&w=2 */
928 int git_buf_unquote(git_buf
*buf
)
935 if (buf
->size
< 2 || buf
->ptr
[0] != '"' || buf
->ptr
[buf
->size
-1] != '"')
938 for (i
= 0, j
= 1; j
< buf
->size
-1; i
++, j
++) {
942 if (j
== buf
->size
-2)
948 /* \" or \\ simply copy the char in */
952 /* add the appropriate escaped char */
953 case 'a': ch
= '\a'; break;
954 case 'b': ch
= '\b'; break;
955 case 'f': ch
= '\f'; break;
956 case 'n': ch
= '\n'; break;
957 case 'r': ch
= '\r'; break;
958 case 't': ch
= '\t'; break;
959 case 'v': ch
= '\v'; break;
961 /* \xyz digits convert to the char*/
962 case '0': case '1': case '2':
963 if (j
== buf
->size
-3) {
964 giterr_set(GITERR_INVALID
,
965 "Truncated quoted character \\%c", ch
);
969 if (buf
->ptr
[j
+1] < '0' || buf
->ptr
[j
+1] > '7' ||
970 buf
->ptr
[j
+2] < '0' || buf
->ptr
[j
+2] > '7') {
971 giterr_set(GITERR_INVALID
,
972 "Truncated quoted character \\%c%c%c",
973 buf
->ptr
[j
], buf
->ptr
[j
+1], buf
->ptr
[j
+2]);
977 ch
= ((buf
->ptr
[j
] - '0') << 6) |
978 ((buf
->ptr
[j
+1] - '0') << 3) |
979 (buf
->ptr
[j
+2] - '0');
984 giterr_set(GITERR_INVALID
, "Invalid quoted character \\%c", ch
);
998 giterr_set(GITERR_INVALID
, "Invalid quoted line");