]>
git.proxmox.com Git - libgit2.git/blob - src/buf_text.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 int git_buf_text_puts_escaped(
12 const char *esc_chars
,
16 size_t total
= 0, esc_len
= strlen(esc_with
), count
, alloclen
;
21 for (scan
= string
; *scan
; ) {
22 /* count run of non-escaped characters */
23 count
= strcspn(scan
, esc_chars
);
26 /* count run of escaped characters */
27 count
= strspn(scan
, esc_chars
);
28 total
+= count
* (esc_len
+ 1);
32 GITERR_CHECK_ALLOC_ADD(&alloclen
, total
, 1);
33 if (git_buf_grow_by(buf
, alloclen
) < 0)
36 for (scan
= string
; *scan
; ) {
37 count
= strcspn(scan
, esc_chars
);
39 memmove(buf
->ptr
+ buf
->size
, scan
, count
);
43 for (count
= strspn(scan
, esc_chars
); count
> 0; --count
) {
44 /* copy escape sequence */
45 memmove(buf
->ptr
+ buf
->size
, esc_with
, esc_len
);
47 /* copy character to be escaped */
48 buf
->ptr
[buf
->size
] = *scan
;
54 buf
->ptr
[buf
->size
] = '\0';
59 void git_buf_text_unescape(git_buf
*buf
)
61 buf
->size
= git__unescape(buf
->ptr
);
64 int git_buf_text_crlf_to_lf(git_buf
*tgt
, const git_buf
*src
)
66 const char *scan
= src
->ptr
;
67 const char *scan_end
= src
->ptr
+ src
->size
;
68 const char *next
= memchr(scan
, '\r', src
->size
);
75 return git_buf_set(tgt
, src
->ptr
, src
->size
);
77 /* reduce reallocs while in the loop */
78 GITERR_CHECK_ALLOC_ADD(&new_size
, src
->size
, 1);
79 if (git_buf_grow(tgt
, new_size
) < 0)
85 /* Find the next \r and copy whole chunk up to there to tgt */
86 for (; next
; scan
= next
+ 1, next
= memchr(scan
, '\r', scan_end
- scan
)) {
88 size_t copylen
= (size_t)(next
- scan
);
89 memcpy(out
, scan
, copylen
);
93 /* Do not drop \r unless it is followed by \n */
94 if (next
+ 1 == scan_end
|| next
[1] != '\n')
98 /* Copy remaining input into dest */
99 if (scan
< scan_end
) {
100 size_t remaining
= (size_t)(scan_end
- scan
);
101 memcpy(out
, scan
, remaining
);
105 tgt
->size
= (size_t)(out
- tgt
->ptr
);
106 tgt
->ptr
[tgt
->size
] = '\0';
111 int git_buf_text_lf_to_crlf(git_buf
*tgt
, const git_buf
*src
)
113 const char *start
= src
->ptr
;
114 const char *end
= start
+ src
->size
;
115 const char *scan
= start
;
116 const char *next
= memchr(scan
, '\n', src
->size
);
122 return git_buf_set(tgt
, src
->ptr
, src
->size
);
124 /* attempt to reduce reallocs while in the loop */
125 GITERR_CHECK_ALLOC_ADD(&alloclen
, src
->size
, src
->size
>> 4);
126 GITERR_CHECK_ALLOC_ADD(&alloclen
, alloclen
, 1);
127 if (git_buf_grow(tgt
, alloclen
) < 0)
131 for (; next
; scan
= next
+ 1, next
= memchr(scan
, '\n', end
- scan
)) {
132 size_t copylen
= next
- scan
;
134 /* if we find mixed line endings, carry on */
135 if (copylen
&& next
[-1] == '\r')
138 GITERR_CHECK_ALLOC_ADD(&alloclen
, copylen
, 3);
139 if (git_buf_grow_by(tgt
, alloclen
) < 0)
143 memcpy(tgt
->ptr
+ tgt
->size
, scan
, copylen
);
144 tgt
->size
+= copylen
;
147 tgt
->ptr
[tgt
->size
++] = '\r';
148 tgt
->ptr
[tgt
->size
++] = '\n';
151 tgt
->ptr
[tgt
->size
] = '\0';
152 return git_buf_put(tgt
, scan
, end
- scan
);
155 int git_buf_text_common_prefix(git_buf
*buf
, const git_strarray
*strings
)
158 const char *str
, *pfx
;
162 if (!strings
|| !strings
->count
)
165 /* initialize common prefix to first string */
166 if (git_buf_sets(buf
, strings
->strings
[0]) < 0)
169 /* go through the rest of the strings, truncating to shared prefix */
170 for (i
= 1; i
< strings
->count
; ++i
) {
172 for (str
= strings
->strings
[i
], pfx
= buf
->ptr
;
173 *str
&& *str
== *pfx
; str
++, pfx
++)
176 git_buf_truncate(buf
, pfx
- buf
->ptr
);
185 bool git_buf_text_is_binary(const git_buf
*buf
)
187 const char *scan
= buf
->ptr
, *end
= buf
->ptr
+ buf
->size
;
189 int printable
= 0, nonprintable
= 0;
191 scan
+= git_buf_text_detect_bom(&bom
, buf
, 0);
193 if (bom
> GIT_BOM_UTF8
)
197 unsigned char c
= *scan
++;
199 /* Printable characters are those above SPACE (0x1F) excluding DEL,
200 * and including BS, ESC and FF.
202 if ((c
> 0x1F && c
!= 127) || c
== '\b' || c
== '\033' || c
== '\014')
206 else if (!git__isspace(c
))
210 return ((printable
>> 7) < nonprintable
);
213 bool git_buf_text_contains_nul(const git_buf
*buf
)
215 return (memchr(buf
->ptr
, '\0', buf
->size
) != NULL
);
218 int git_buf_text_detect_bom(git_bom_t
*bom
, const git_buf
*buf
, size_t offset
)
224 /* need at least 2 bytes after offset to look for any BOM */
225 if (buf
->size
< offset
+ 2)
228 ptr
= buf
->ptr
+ offset
;
229 len
= buf
->size
- offset
;
233 if (len
>= 4 && ptr
[0] == 0 && ptr
[1] == '\xFE' && ptr
[2] == '\xFF') {
234 *bom
= GIT_BOM_UTF32_BE
;
239 if (len
>= 3 && ptr
[0] == '\xBB' && ptr
[1] == '\xBF') {
245 if (*ptr
== '\xFF') {
246 *bom
= GIT_BOM_UTF16_BE
;
253 if (len
>= 4 && ptr
[1] == 0 && ptr
[2] == 0) {
254 *bom
= GIT_BOM_UTF32_LE
;
257 *bom
= GIT_BOM_UTF16_LE
;
268 bool git_buf_text_gather_stats(
269 git_buf_text_stats
*stats
, const git_buf
*buf
, bool skip_bom
)
271 const char *scan
= buf
->ptr
, *end
= buf
->ptr
+ buf
->size
;
274 memset(stats
, 0, sizeof(*stats
));
277 skip
= git_buf_text_detect_bom(&stats
->bom
, buf
, 0);
281 /* Ignore EOF character */
282 if (buf
->size
> 0 && end
[-1] == '\032')
287 unsigned char c
= *scan
++;
289 if (c
> 0x1F && c
!= 0x7F)
294 stats
->nonprintable
++;
301 if (scan
< end
&& *scan
== '\n')
304 case '\t': case '\f': case '\v': case '\b': case 0x1b: /*ESC*/
308 stats
->nonprintable
++;
313 return (stats
->nul
> 0 ||
314 ((stats
->printable
>> 7) < stats
->nonprintable
));