]>
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 git_error_set(GIT_ERROR_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_dispose(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_free(git_buf
*buf
)
131 git_buf_dispose(buf
);
134 void git_buf_sanitize(git_buf
*buf
)
136 if (buf
->ptr
== NULL
) {
137 assert(buf
->size
== 0 && buf
->asize
== 0);
138 buf
->ptr
= git_buf__initbuf
;
139 } else if (buf
->asize
> buf
->size
)
140 buf
->ptr
[buf
->size
] = '\0';
143 void git_buf_clear(git_buf
*buf
)
148 buf
->ptr
= git_buf__initbuf
;
156 int git_buf_set(git_buf
*buf
, const void *data
, size_t len
)
160 if (len
== 0 || data
== NULL
) {
163 if (data
!= buf
->ptr
) {
164 GIT_ERROR_CHECK_ALLOC_ADD(&alloclen
, len
, 1);
165 ENSURE_SIZE(buf
, alloclen
);
166 memmove(buf
->ptr
, data
, len
);
170 if (buf
->asize
> buf
->size
)
171 buf
->ptr
[buf
->size
] = '\0';
177 int git_buf_is_binary(const git_buf
*buf
)
179 return git_buf_text_is_binary(buf
);
182 int git_buf_contains_nul(const git_buf
*buf
)
184 return git_buf_text_contains_nul(buf
);
187 int git_buf_sets(git_buf
*buf
, const char *string
)
189 return git_buf_set(buf
, string
, string
? strlen(string
) : 0);
192 int git_buf_putc(git_buf
*buf
, char c
)
195 GIT_ERROR_CHECK_ALLOC_ADD(&new_size
, buf
->size
, 2);
196 ENSURE_SIZE(buf
, new_size
);
197 buf
->ptr
[buf
->size
++] = c
;
198 buf
->ptr
[buf
->size
] = '\0';
202 int git_buf_putcn(git_buf
*buf
, char c
, size_t len
)
205 GIT_ERROR_CHECK_ALLOC_ADD(&new_size
, buf
->size
, len
);
206 GIT_ERROR_CHECK_ALLOC_ADD(&new_size
, new_size
, 1);
207 ENSURE_SIZE(buf
, new_size
);
208 memset(buf
->ptr
+ buf
->size
, c
, len
);
210 buf
->ptr
[buf
->size
] = '\0';
214 int git_buf_put(git_buf
*buf
, const char *data
, size_t len
)
221 GIT_ERROR_CHECK_ALLOC_ADD(&new_size
, buf
->size
, len
);
222 GIT_ERROR_CHECK_ALLOC_ADD(&new_size
, new_size
, 1);
223 ENSURE_SIZE(buf
, new_size
);
224 memmove(buf
->ptr
+ buf
->size
, data
, len
);
226 buf
->ptr
[buf
->size
] = '\0';
231 int git_buf_puts(git_buf
*buf
, const char *string
)
234 return git_buf_put(buf
, string
, strlen(string
));
237 static const char base64_encode
[] =
238 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
240 int git_buf_encode_base64(git_buf
*buf
, const char *data
, size_t len
)
242 size_t extra
= len
% 3;
243 uint8_t *write
, a
, b
, c
;
244 const uint8_t *read
= (const uint8_t *)data
;
245 size_t blocks
= (len
/ 3) + !!extra
, alloclen
;
247 GIT_ERROR_CHECK_ALLOC_ADD(&blocks
, blocks
, 1);
248 GIT_ERROR_CHECK_ALLOC_MULTIPLY(&alloclen
, blocks
, 4);
249 GIT_ERROR_CHECK_ALLOC_ADD(&alloclen
, alloclen
, buf
->size
);
251 ENSURE_SIZE(buf
, alloclen
);
252 write
= (uint8_t *)&buf
->ptr
[buf
->size
];
254 /* convert each run of 3 bytes into 4 output bytes */
255 for (len
-= extra
; len
> 0; len
-= 3) {
260 *write
++ = base64_encode
[a
>> 2];
261 *write
++ = base64_encode
[(a
& 0x03) << 4 | b
>> 4];
262 *write
++ = base64_encode
[(b
& 0x0f) << 2 | c
>> 6];
263 *write
++ = base64_encode
[c
& 0x3f];
268 b
= (extra
> 1) ? *read
++ : 0;
270 *write
++ = base64_encode
[a
>> 2];
271 *write
++ = base64_encode
[(a
& 0x03) << 4 | b
>> 4];
272 *write
++ = (extra
> 1) ? base64_encode
[(b
& 0x0f) << 2] : '=';
276 buf
->size
= ((char *)write
) - buf
->ptr
;
277 buf
->ptr
[buf
->size
] = '\0';
282 /* The inverse of base64_encode */
283 static const int8_t base64_decode
[] = {
284 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
285 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
286 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
287 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, 0, -1, -1,
288 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
289 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
290 -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
291 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -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,
295 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
296 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
297 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
298 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
299 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
302 int git_buf_decode_base64(git_buf
*buf
, const char *base64
, size_t len
)
306 size_t orig_size
= buf
->size
, new_size
;
309 git_error_set(GIT_ERROR_INVALID
, "invalid base64 input");
313 assert(len
% 4 == 0);
314 GIT_ERROR_CHECK_ALLOC_ADD(&new_size
, (len
/ 4 * 3), buf
->size
);
315 GIT_ERROR_CHECK_ALLOC_ADD(&new_size
, new_size
, 1);
316 ENSURE_SIZE(buf
, new_size
);
318 for (i
= 0; i
< len
; i
+= 4) {
319 if ((a
= base64_decode
[(unsigned char)base64
[i
]]) < 0 ||
320 (b
= base64_decode
[(unsigned char)base64
[i
+1]]) < 0 ||
321 (c
= base64_decode
[(unsigned char)base64
[i
+2]]) < 0 ||
322 (d
= base64_decode
[(unsigned char)base64
[i
+3]]) < 0) {
323 buf
->size
= orig_size
;
324 buf
->ptr
[buf
->size
] = '\0';
326 git_error_set(GIT_ERROR_INVALID
, "invalid base64 input");
330 buf
->ptr
[buf
->size
++] = ((a
<< 2) | (b
& 0x30) >> 4);
331 buf
->ptr
[buf
->size
++] = ((b
& 0x0f) << 4) | ((c
& 0x3c) >> 2);
332 buf
->ptr
[buf
->size
++] = (c
& 0x03) << 6 | (d
& 0x3f);
335 buf
->ptr
[buf
->size
] = '\0';
339 static const char base85_encode
[] =
340 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!#$%&()*+-;<=>?@^_`{|}~";
342 int git_buf_encode_base85(git_buf
*buf
, const char *data
, size_t len
)
344 size_t blocks
= (len
/ 4) + !!(len
% 4), alloclen
;
346 GIT_ERROR_CHECK_ALLOC_MULTIPLY(&alloclen
, blocks
, 5);
347 GIT_ERROR_CHECK_ALLOC_ADD(&alloclen
, alloclen
, buf
->size
);
348 GIT_ERROR_CHECK_ALLOC_ADD(&alloclen
, alloclen
, 1);
350 ENSURE_SIZE(buf
, alloclen
);
357 for (i
= 24; i
>= 0; i
-= 8) {
358 uint8_t ch
= *data
++;
365 for (i
= 4; i
>= 0; i
--) {
369 b85
[i
] = base85_encode
[val
];
372 for (i
= 0; i
< 5; i
++)
373 buf
->ptr
[buf
->size
++] = b85
[i
];
376 buf
->ptr
[buf
->size
] = '\0';
381 /* The inverse of base85_encode */
382 static const int8_t base85_decode
[] = {
383 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
384 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
385 -1, 63, -1, 64, 65, 66, 67, -1, 68, 69, 70, 71, -1, 72, -1, -1,
386 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, -1, 73, 74, 75, 76, 77,
387 78, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
388 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, -1, -1, -1, 79, 80,
389 81, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,
390 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 82, 83, 84, 85, -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,
394 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
395 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
396 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
397 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
398 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
401 int git_buf_decode_base85(
407 size_t orig_size
= buf
->size
, new_size
;
409 if (base85_len
% 5 ||
410 output_len
> base85_len
* 4 / 5) {
411 git_error_set(GIT_ERROR_INVALID
, "invalid base85 input");
415 GIT_ERROR_CHECK_ALLOC_ADD(&new_size
, output_len
, buf
->size
);
416 GIT_ERROR_CHECK_ALLOC_ADD(&new_size
, new_size
, 1);
417 ENSURE_SIZE(buf
, new_size
);
425 de
= base85_decode
[ch
];
432 de
= base85_decode
[ch
];
436 /* Detect overflow. */
437 if (0xffffffff / 85 < acc
||
438 0xffffffff - de
< (acc
*= 85))
443 cnt
= (output_len
< 4) ? (int)output_len
: 4;
446 acc
= (acc
<< 8) | (acc
>> 24);
447 buf
->ptr
[buf
->size
++] = acc
;
451 buf
->ptr
[buf
->size
] = 0;
456 buf
->size
= orig_size
;
457 buf
->ptr
[buf
->size
] = '\0';
459 git_error_set(GIT_ERROR_INVALID
, "invalid base85 input");
463 #define HEX_DECODE(c) ((c | 32) % 39 - 9)
465 int git_buf_decode_percent(
470 size_t str_pos
, new_size
;
472 GIT_ERROR_CHECK_ALLOC_ADD(&new_size
, buf
->size
, str_len
);
473 GIT_ERROR_CHECK_ALLOC_ADD(&new_size
, new_size
, 1);
474 ENSURE_SIZE(buf
, new_size
);
476 for (str_pos
= 0; str_pos
< str_len
; buf
->size
++, str_pos
++) {
477 if (str
[str_pos
] == '%' &&
478 str_len
> str_pos
+ 2 &&
479 isxdigit(str
[str_pos
+ 1]) &&
480 isxdigit(str
[str_pos
+ 2])) {
481 buf
->ptr
[buf
->size
] = (HEX_DECODE(str
[str_pos
+ 1]) << 4) +
482 HEX_DECODE(str
[str_pos
+ 2]);
485 buf
->ptr
[buf
->size
] = str
[str_pos
];
489 buf
->ptr
[buf
->size
] = '\0';
493 int git_buf_vprintf(git_buf
*buf
, const char *format
, va_list ap
)
495 size_t expected_size
, new_size
;
498 GIT_ERROR_CHECK_ALLOC_MULTIPLY(&expected_size
, strlen(format
), 2);
499 GIT_ERROR_CHECK_ALLOC_ADD(&expected_size
, expected_size
, buf
->size
);
500 ENSURE_SIZE(buf
, expected_size
);
507 buf
->ptr
+ buf
->size
,
508 buf
->asize
- buf
->size
,
516 buf
->ptr
= git_buf__oom
;
520 if ((size_t)len
+ 1 <= buf
->asize
- buf
->size
) {
525 GIT_ERROR_CHECK_ALLOC_ADD(&new_size
, buf
->size
, len
);
526 GIT_ERROR_CHECK_ALLOC_ADD(&new_size
, new_size
, 1);
527 ENSURE_SIZE(buf
, new_size
);
533 int git_buf_printf(git_buf
*buf
, const char *format
, ...)
538 va_start(ap
, format
);
539 r
= git_buf_vprintf(buf
, format
, ap
);
545 void git_buf_copy_cstr(char *data
, size_t datasize
, const git_buf
*buf
)
549 assert(data
&& datasize
&& buf
);
553 if (buf
->size
== 0 || buf
->asize
<= 0)
557 if (copylen
> datasize
- 1)
558 copylen
= datasize
- 1;
559 memmove(data
, buf
->ptr
, copylen
);
560 data
[copylen
] = '\0';
563 void git_buf_consume(git_buf
*buf
, const char *end
)
565 if (end
> buf
->ptr
&& end
<= buf
->ptr
+ buf
->size
) {
566 size_t consumed
= end
- buf
->ptr
;
567 memmove(buf
->ptr
, end
, buf
->size
- consumed
);
568 buf
->size
-= consumed
;
569 buf
->ptr
[buf
->size
] = '\0';
573 void git_buf_truncate(git_buf
*buf
, size_t len
)
575 if (len
>= buf
->size
)
579 if (buf
->size
< buf
->asize
)
580 buf
->ptr
[buf
->size
] = '\0';
583 void git_buf_shorten(git_buf
*buf
, size_t amount
)
585 if (buf
->size
> amount
)
586 git_buf_truncate(buf
, buf
->size
- amount
);
591 void git_buf_rtruncate_at_char(git_buf
*buf
, char separator
)
593 ssize_t idx
= git_buf_rfind_next(buf
, separator
);
594 git_buf_truncate(buf
, idx
< 0 ? 0 : (size_t)idx
);
597 void git_buf_swap(git_buf
*buf_a
, git_buf
*buf_b
)
604 char *git_buf_detach(git_buf
*buf
)
606 char *data
= buf
->ptr
;
608 if (buf
->asize
== 0 || buf
->ptr
== git_buf__oom
)
611 git_buf_init(buf
, 0);
616 int git_buf_attach(git_buf
*buf
, char *ptr
, size_t asize
)
618 git_buf_dispose(buf
);
622 buf
->size
= strlen(ptr
);
624 buf
->asize
= (asize
< buf
->size
) ? buf
->size
+ 1 : asize
;
625 else /* pass 0 to fall back on strlen + 1 */
626 buf
->asize
= buf
->size
+ 1;
629 ENSURE_SIZE(buf
, asize
);
633 void git_buf_attach_notowned(git_buf
*buf
, const char *ptr
, size_t size
)
635 if (git_buf_is_allocated(buf
))
636 git_buf_dispose(buf
);
639 git_buf_init(buf
, 0);
641 buf
->ptr
= (char *)ptr
;
647 int git_buf_join_n(git_buf
*buf
, char separator
, int nbuf
, ...)
651 size_t total_size
= 0, original_size
= buf
->size
;
652 char *out
, *original
= buf
->ptr
;
654 if (buf
->size
> 0 && buf
->ptr
[buf
->size
- 1] != separator
)
655 ++total_size
; /* space for initial separator */
657 /* Make two passes to avoid multiple reallocation */
660 for (i
= 0; i
< nbuf
; ++i
) {
664 segment
= va_arg(ap
, const char *);
668 segment_len
= strlen(segment
);
670 GIT_ERROR_CHECK_ALLOC_ADD(&total_size
, total_size
, segment_len
);
672 if (segment_len
== 0 || segment
[segment_len
- 1] != separator
)
673 GIT_ERROR_CHECK_ALLOC_ADD(&total_size
, total_size
, 1);
677 /* expand buffer if needed */
681 GIT_ERROR_CHECK_ALLOC_ADD(&total_size
, total_size
, 1);
682 if (git_buf_grow_by(buf
, total_size
) < 0)
685 out
= buf
->ptr
+ buf
->size
;
687 /* append separator to existing buf if needed */
688 if (buf
->size
> 0 && out
[-1] != separator
)
692 for (i
= 0; i
< nbuf
; ++i
) {
696 segment
= va_arg(ap
, const char *);
700 /* deal with join that references buffer's original content */
701 if (segment
>= original
&& segment
< original
+ original_size
) {
702 size_t offset
= (segment
- original
);
703 segment
= buf
->ptr
+ offset
;
704 segment_len
= original_size
- offset
;
706 segment_len
= strlen(segment
);
709 /* skip leading separators */
710 if (out
> buf
->ptr
&& out
[-1] == separator
)
711 while (segment_len
> 0 && *segment
== separator
) {
716 /* copy over next buffer */
717 if (segment_len
> 0) {
718 memmove(out
, segment
, segment_len
);
722 /* append trailing separator (except for last item) */
723 if (i
< nbuf
- 1 && out
> buf
->ptr
&& out
[-1] != separator
)
728 /* set size based on num characters actually written */
729 buf
->size
= out
- buf
->ptr
;
730 buf
->ptr
[buf
->size
] = '\0';
741 size_t strlen_a
= str_a
? strlen(str_a
) : 0;
742 size_t strlen_b
= strlen(str_b
);
745 ssize_t offset_a
= -1;
747 /* not safe to have str_b point internally to the buffer */
748 assert(str_b
< buf
->ptr
|| str_b
>= buf
->ptr
+ buf
->size
);
750 /* figure out if we need to insert a separator */
751 if (separator
&& strlen_a
) {
752 while (*str_b
== separator
) { str_b
++; strlen_b
--; }
753 if (str_a
[strlen_a
- 1] != separator
)
757 /* str_a could be part of the buffer */
758 if (str_a
>= buf
->ptr
&& str_a
< buf
->ptr
+ buf
->size
)
759 offset_a
= str_a
- buf
->ptr
;
761 GIT_ERROR_CHECK_ALLOC_ADD(&alloc_len
, strlen_a
, strlen_b
);
762 GIT_ERROR_CHECK_ALLOC_ADD(&alloc_len
, alloc_len
, need_sep
);
763 GIT_ERROR_CHECK_ALLOC_ADD(&alloc_len
, alloc_len
, 1);
764 ENSURE_SIZE(buf
, alloc_len
);
766 /* fix up internal pointers */
768 str_a
= buf
->ptr
+ offset_a
;
770 /* do the actual copying */
771 if (offset_a
!= 0 && str_a
)
772 memmove(buf
->ptr
, str_a
, strlen_a
);
774 buf
->ptr
[strlen_a
] = separator
;
775 memcpy(buf
->ptr
+ strlen_a
+ need_sep
, str_b
, strlen_b
);
777 buf
->size
= strlen_a
+ strlen_b
+ need_sep
;
778 buf
->ptr
[buf
->size
] = '\0';
790 size_t len_a
= strlen(str_a
),
791 len_b
= strlen(str_b
),
792 len_c
= strlen(str_c
),
794 int sep_a
= 0, sep_b
= 0;
797 /* for this function, disallow pointers into the existing buffer */
798 assert(str_a
< buf
->ptr
|| str_a
>= buf
->ptr
+ buf
->size
);
799 assert(str_b
< buf
->ptr
|| str_b
>= buf
->ptr
+ buf
->size
);
800 assert(str_c
< buf
->ptr
|| str_c
>= buf
->ptr
+ buf
->size
);
804 while (*str_b
== separator
) { str_b
++; len_b
--; }
805 sep_a
= (str_a
[len_a
- 1] != separator
);
807 if (len_a
> 0 || len_b
> 0)
808 while (*str_c
== separator
) { str_c
++; len_c
--; }
810 sep_b
= (str_b
[len_b
- 1] != separator
);
813 GIT_ERROR_CHECK_ALLOC_ADD(&len_total
, len_a
, sep_a
);
814 GIT_ERROR_CHECK_ALLOC_ADD(&len_total
, len_total
, len_b
);
815 GIT_ERROR_CHECK_ALLOC_ADD(&len_total
, len_total
, sep_b
);
816 GIT_ERROR_CHECK_ALLOC_ADD(&len_total
, len_total
, len_c
);
817 GIT_ERROR_CHECK_ALLOC_ADD(&len_total
, len_total
, 1);
818 ENSURE_SIZE(buf
, len_total
);
823 memcpy(tgt
, str_a
, len_a
);
829 memcpy(tgt
, str_b
, len_b
);
835 memcpy(tgt
, str_c
, len_c
);
837 buf
->size
= len_a
+ sep_a
+ len_b
+ sep_b
+ len_c
;
838 buf
->ptr
[buf
->size
] = '\0';
843 void git_buf_rtrim(git_buf
*buf
)
845 while (buf
->size
> 0) {
846 if (!git__isspace(buf
->ptr
[buf
->size
- 1]))
852 if (buf
->asize
> buf
->size
)
853 buf
->ptr
[buf
->size
] = '\0';
856 int git_buf_cmp(const git_buf
*a
, const git_buf
*b
)
858 int result
= memcmp(a
->ptr
, b
->ptr
, min(a
->size
, b
->size
));
859 return (result
!= 0) ? result
:
860 (a
->size
< b
->size
) ? -1 : (a
->size
> b
->size
) ? 1 : 0;
871 size_t new_size
, alloc_size
;
873 assert(buf
&& where
<= buf
->size
&& nb_to_remove
<= buf
->size
- where
);
875 splice_loc
= buf
->ptr
+ where
;
877 /* Ported from git.git
878 * https://github.com/git/git/blob/16eed7c/strbuf.c#L159-176
880 GIT_ERROR_CHECK_ALLOC_ADD(&new_size
, (buf
->size
- nb_to_remove
), nb_to_insert
);
881 GIT_ERROR_CHECK_ALLOC_ADD(&alloc_size
, new_size
, 1);
882 ENSURE_SIZE(buf
, alloc_size
);
884 memmove(splice_loc
+ nb_to_insert
,
885 splice_loc
+ nb_to_remove
,
886 buf
->size
- where
- nb_to_remove
);
888 memcpy(splice_loc
, data
, nb_to_insert
);
890 buf
->size
= new_size
;
891 buf
->ptr
[buf
->size
] = '\0';
895 /* Quote per http://marc.info/?l=git&m=112927316408690&w=2 */
896 int git_buf_quote(git_buf
*buf
)
898 const char whitespace
[] = { 'a', 'b', 't', 'n', 'v', 'f', 'r' };
899 git_buf quoted
= GIT_BUF_INIT
;
904 /* walk to the first char that needs quoting */
905 if (buf
->size
&& buf
->ptr
[0] == '!')
908 for (i
= 0; !quote
&& i
< buf
->size
; i
++) {
909 if (buf
->ptr
[i
] == '"' || buf
->ptr
[i
] == '\\' ||
910 buf
->ptr
[i
] < ' ' || buf
->ptr
[i
] > '~') {
919 git_buf_putc("ed
, '"');
920 git_buf_put("ed
, buf
->ptr
, i
);
922 for (; i
< buf
->size
; i
++) {
923 /* whitespace - use the map above, which is ordered by ascii value */
924 if (buf
->ptr
[i
] >= '\a' && buf
->ptr
[i
] <= '\r') {
925 git_buf_putc("ed
, '\\');
926 git_buf_putc("ed
, whitespace
[buf
->ptr
[i
] - '\a']);
929 /* double quote and backslash must be escaped */
930 else if (buf
->ptr
[i
] == '"' || buf
->ptr
[i
] == '\\') {
931 git_buf_putc("ed
, '\\');
932 git_buf_putc("ed
, buf
->ptr
[i
]);
935 /* escape anything unprintable as octal */
936 else if (buf
->ptr
[i
] != ' ' &&
937 (buf
->ptr
[i
] < '!' || buf
->ptr
[i
] > '~')) {
938 git_buf_printf("ed
, "\\%03o", (unsigned char)buf
->ptr
[i
]);
941 /* yay, printable! */
943 git_buf_putc("ed
, buf
->ptr
[i
]);
947 git_buf_putc("ed
, '"');
949 if (git_buf_oom("ed
)) {
954 git_buf_swap("ed
, buf
);
957 git_buf_dispose("ed
);
961 /* Unquote per http://marc.info/?l=git&m=112927316408690&w=2 */
962 int git_buf_unquote(git_buf
*buf
)
969 if (buf
->size
< 2 || buf
->ptr
[0] != '"' || buf
->ptr
[buf
->size
-1] != '"')
972 for (i
= 0, j
= 1; j
< buf
->size
-1; i
++, j
++) {
976 if (j
== buf
->size
-2)
982 /* \" or \\ simply copy the char in */
986 /* add the appropriate escaped char */
987 case 'a': ch
= '\a'; break;
988 case 'b': ch
= '\b'; break;
989 case 'f': ch
= '\f'; break;
990 case 'n': ch
= '\n'; break;
991 case 'r': ch
= '\r'; break;
992 case 't': ch
= '\t'; break;
993 case 'v': ch
= '\v'; break;
995 /* \xyz digits convert to the char*/
996 case '0': case '1': case '2': case '3':
997 if (j
== buf
->size
-3) {
998 git_error_set(GIT_ERROR_INVALID
,
999 "truncated quoted character \\%c", ch
);
1003 if (buf
->ptr
[j
+1] < '0' || buf
->ptr
[j
+1] > '7' ||
1004 buf
->ptr
[j
+2] < '0' || buf
->ptr
[j
+2] > '7') {
1005 git_error_set(GIT_ERROR_INVALID
,
1006 "truncated quoted character \\%c%c%c",
1007 buf
->ptr
[j
], buf
->ptr
[j
+1], buf
->ptr
[j
+2]);
1011 ch
= ((buf
->ptr
[j
] - '0') << 6) |
1012 ((buf
->ptr
[j
+1] - '0') << 3) |
1013 (buf
->ptr
[j
+2] - '0');
1018 git_error_set(GIT_ERROR_INVALID
, "invalid quoted character \\%c", ch
);
1032 git_error_set(GIT_ERROR_INVALID
, "invalid quoted line");