mirror of
https://github.com/git/git.git
synced 2024-09-22 06:42:22 +02:00
convert: track state in LF-to-CRLF filter
There may not be enough space to store CRLF in the output. If we don't fill the buffer, then the filter will keep getting called with the same short buffer and will loop forever. Instead, always store the CR and record whether there's a missing LF if so we store it in the output buffer the next time the function gets called. Reported-by: Henrik Grubbström <grubba@roxen.com> Signed-off-by: Carlos Martín Nieto <cmn@elego.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
parent
703f05ad58
commit
284e3d280e
48
convert.c
48
convert.c
@ -876,24 +876,39 @@ int is_null_stream_filter(struct stream_filter *filter)
|
|||||||
/*
|
/*
|
||||||
* LF-to-CRLF filter
|
* LF-to-CRLF filter
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
struct lf_to_crlf_filter {
|
||||||
|
struct stream_filter filter;
|
||||||
|
int want_lf;
|
||||||
|
};
|
||||||
|
|
||||||
static int lf_to_crlf_filter_fn(struct stream_filter *filter,
|
static int lf_to_crlf_filter_fn(struct stream_filter *filter,
|
||||||
const char *input, size_t *isize_p,
|
const char *input, size_t *isize_p,
|
||||||
char *output, size_t *osize_p)
|
char *output, size_t *osize_p)
|
||||||
{
|
{
|
||||||
size_t count;
|
size_t count, o = 0;
|
||||||
|
struct lf_to_crlf_filter *lf_to_crlf = (struct lf_to_crlf_filter *)filter;
|
||||||
|
|
||||||
|
/* Output a pending LF if we need to */
|
||||||
|
if (lf_to_crlf->want_lf) {
|
||||||
|
output[o++] = '\n';
|
||||||
|
lf_to_crlf->want_lf = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (!input)
|
if (!input)
|
||||||
return 0; /* we do not keep any states */
|
return 0; /* We've already dealt with the state */
|
||||||
|
|
||||||
count = *isize_p;
|
count = *isize_p;
|
||||||
if (count) {
|
if (count) {
|
||||||
size_t i, o;
|
size_t i;
|
||||||
for (i = o = 0; o < *osize_p && i < count; i++) {
|
for (i = 0; o < *osize_p && i < count; i++) {
|
||||||
char ch = input[i];
|
char ch = input[i];
|
||||||
if (ch == '\n') {
|
if (ch == '\n') {
|
||||||
if (o + 1 < *osize_p)
|
|
||||||
output[o++] = '\r';
|
output[o++] = '\r';
|
||||||
else
|
if (o >= *osize_p) {
|
||||||
break;
|
lf_to_crlf->want_lf = 1;
|
||||||
|
continue; /* We need to increase i */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
output[o++] = ch;
|
output[o++] = ch;
|
||||||
}
|
}
|
||||||
@ -904,15 +919,24 @@ static int lf_to_crlf_filter_fn(struct stream_filter *filter,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void lf_to_crlf_free_fn(struct stream_filter *filter)
|
||||||
|
{
|
||||||
|
free(filter);
|
||||||
|
}
|
||||||
|
|
||||||
static struct stream_filter_vtbl lf_to_crlf_vtbl = {
|
static struct stream_filter_vtbl lf_to_crlf_vtbl = {
|
||||||
lf_to_crlf_filter_fn,
|
lf_to_crlf_filter_fn,
|
||||||
null_free_fn,
|
lf_to_crlf_free_fn,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct stream_filter lf_to_crlf_filter_singleton = {
|
static struct stream_filter *lf_to_crlf_filter(void)
|
||||||
&lf_to_crlf_vtbl,
|
{
|
||||||
};
|
struct lf_to_crlf_filter *lf_to_crlf = xmalloc(sizeof(*lf_to_crlf));
|
||||||
|
|
||||||
|
lf_to_crlf->filter.vtbl = &lf_to_crlf_vtbl;
|
||||||
|
lf_to_crlf->want_lf = 0;
|
||||||
|
return (struct stream_filter *)lf_to_crlf;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Cascade filter
|
* Cascade filter
|
||||||
@ -1194,7 +1218,7 @@ struct stream_filter *get_stream_filter(const char *path, const unsigned char *s
|
|||||||
|
|
||||||
else if (output_eol(crlf_action) == EOL_CRLF &&
|
else if (output_eol(crlf_action) == EOL_CRLF &&
|
||||||
!(crlf_action == CRLF_AUTO || crlf_action == CRLF_GUESS))
|
!(crlf_action == CRLF_AUTO || crlf_action == CRLF_GUESS))
|
||||||
filter = cascade_filter(filter, &lf_to_crlf_filter_singleton);
|
filter = cascade_filter(filter, lf_to_crlf_filter());
|
||||||
|
|
||||||
return filter;
|
return filter;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user