Merge branch 'bc/mailsplit-cr-at-eol'
* bc/mailsplit-cr-at-eol: Allow mailsplit (and hence git-am) to handle mails with CRLF line-endings builtin-mailsplit.c: remove read_line_with_nul() since it is no longer used builtin-mailinfo,builtin-mailsplit: use strbufs strbuf: add new function strbuf_getwholeline()
This commit is contained in:
commit
bcd45e27d8
@ -765,7 +765,6 @@ static void handle_filter(struct strbuf *line)
|
||||
|
||||
static void handle_body(void)
|
||||
{
|
||||
int len = 0;
|
||||
struct strbuf prev = STRBUF_INIT;
|
||||
|
||||
/* Skip up to the first boundary */
|
||||
@ -775,8 +774,6 @@ static void handle_body(void)
|
||||
}
|
||||
|
||||
do {
|
||||
strbuf_setlen(&line, line.len + len);
|
||||
|
||||
/* process any boundary lines */
|
||||
if (*content_top && is_multipart_boundary(&line)) {
|
||||
/* flush any leftover */
|
||||
@ -832,10 +829,7 @@ static void handle_body(void)
|
||||
handle_filter(&line);
|
||||
}
|
||||
|
||||
strbuf_reset(&line);
|
||||
if (strbuf_avail(&line) < 100)
|
||||
strbuf_grow(&line, 100);
|
||||
} while ((len = read_line_with_nul(line.buf, strbuf_avail(&line), fin)));
|
||||
} while (!strbuf_getwholeline(&line, fin, '\n'));
|
||||
|
||||
handle_body_out:
|
||||
strbuf_release(&prev);
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "cache.h"
|
||||
#include "builtin.h"
|
||||
#include "string-list.h"
|
||||
#include "strbuf.h"
|
||||
|
||||
static const char git_mailsplit_usage[] =
|
||||
"git mailsplit [-d<prec>] [-f<n>] [-b] -o<directory> [<mbox>|<Maildir>...]";
|
||||
@ -42,26 +43,8 @@ static int is_from_line(const char *line, int len)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Could be as small as 64, enough to hold a Unix "From " line. */
|
||||
static char buf[4096];
|
||||
|
||||
/* We cannot use fgets() because our lines can contain NULs */
|
||||
int read_line_with_nul(char *buf, int size, FILE *in)
|
||||
{
|
||||
int len = 0, c;
|
||||
|
||||
for (;;) {
|
||||
c = getc(in);
|
||||
if (c == EOF)
|
||||
break;
|
||||
buf[len++] = c;
|
||||
if (c == '\n' || len + 1 >= size)
|
||||
break;
|
||||
}
|
||||
buf[len] = '\0';
|
||||
|
||||
return len;
|
||||
}
|
||||
static struct strbuf buf = STRBUF_INIT;
|
||||
static int keep_cr;
|
||||
|
||||
/* Called with the first line (potentially partial)
|
||||
* already in buf[] -- normally that should begin with
|
||||
@ -71,10 +54,9 @@ int read_line_with_nul(char *buf, int size, FILE *in)
|
||||
static int split_one(FILE *mbox, const char *name, int allow_bare)
|
||||
{
|
||||
FILE *output = NULL;
|
||||
int len = strlen(buf);
|
||||
int fd;
|
||||
int status = 0;
|
||||
int is_bare = !is_from_line(buf, len);
|
||||
int is_bare = !is_from_line(buf.buf, buf.len);
|
||||
|
||||
if (is_bare && !allow_bare)
|
||||
goto corrupt;
|
||||
@ -88,20 +70,23 @@ static int split_one(FILE *mbox, const char *name, int allow_bare)
|
||||
* "From " and having something that looks like a date format.
|
||||
*/
|
||||
for (;;) {
|
||||
int is_partial = len && buf[len-1] != '\n';
|
||||
if (!keep_cr && buf.len > 1 && buf.buf[buf.len-1] == '\n' &&
|
||||
buf.buf[buf.len-2] == '\r') {
|
||||
strbuf_setlen(&buf, buf.len-2);
|
||||
strbuf_addch(&buf, '\n');
|
||||
}
|
||||
|
||||
if (fwrite(buf, 1, len, output) != len)
|
||||
if (fwrite(buf.buf, 1, buf.len, output) != buf.len)
|
||||
die_errno("cannot write output");
|
||||
|
||||
len = read_line_with_nul(buf, sizeof(buf), mbox);
|
||||
if (len == 0) {
|
||||
if (strbuf_getwholeline(&buf, mbox, '\n')) {
|
||||
if (feof(mbox)) {
|
||||
status = 1;
|
||||
break;
|
||||
}
|
||||
die_errno("cannot read mbox");
|
||||
}
|
||||
if (!is_partial && !is_bare && is_from_line(buf, len))
|
||||
if (!is_bare && is_from_line(buf.buf, buf.len))
|
||||
break; /* done with one message */
|
||||
}
|
||||
fclose(output);
|
||||
@ -166,7 +151,7 @@ static int split_maildir(const char *maildir, const char *dir,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (fgets(buf, sizeof(buf), f) == NULL) {
|
||||
if (strbuf_getwholeline(&buf, f, '\n')) {
|
||||
error("cannot read mail %s (%s)", file, strerror(errno));
|
||||
goto out;
|
||||
}
|
||||
@ -203,7 +188,7 @@ static int split_mbox(const char *file, const char *dir, int allow_bare,
|
||||
} while (isspace(peek));
|
||||
ungetc(peek, f);
|
||||
|
||||
if (fgets(buf, sizeof(buf), f) == NULL) {
|
||||
if (strbuf_getwholeline(&buf, f, '\n')) {
|
||||
/* empty stdin is OK */
|
||||
if (f != stdin) {
|
||||
error("cannot read mbox %s", file);
|
||||
@ -248,6 +233,8 @@ int cmd_mailsplit(int argc, const char **argv, const char *prefix)
|
||||
nr = strtol(arg+2, NULL, 10);
|
||||
} else if ( arg[1] == 'b' && !arg[2] ) {
|
||||
allow_bare = 1;
|
||||
} else if (!strcmp(arg, "--keep-cr")) {
|
||||
keep_cr = 1;
|
||||
} else if ( arg[1] == 'o' && arg[2] ) {
|
||||
dir = arg+2;
|
||||
} else if ( arg[1] == '-' && !arg[2] ) {
|
||||
|
@ -13,7 +13,6 @@ extern const char git_more_info_string[];
|
||||
extern void list_common_cmds_help(void);
|
||||
extern const char *help_unknown_cmd(const char *cmd);
|
||||
extern void prune_packed_objects(int);
|
||||
extern int read_line_with_nul(char *buf, int size, FILE *file);
|
||||
extern int fmt_merge_msg(int merge_summary, struct strbuf *in,
|
||||
struct strbuf *out);
|
||||
extern int commit_tree(const char *msg, unsigned char *tree,
|
||||
|
@ -211,7 +211,13 @@ check_patch_format () {
|
||||
split_patches () {
|
||||
case "$patch_format" in
|
||||
mbox)
|
||||
git mailsplit -d"$prec" -o"$dotest" -b -- "$@" > "$dotest/last" ||
|
||||
case "$rebasing" in
|
||||
'')
|
||||
keep_cr= ;;
|
||||
?*)
|
||||
keep_cr=--keep-cr ;;
|
||||
esac
|
||||
git mailsplit -d"$prec" -o"$dotest" -b $keep_cr -- "$@" > "$dotest/last" ||
|
||||
clean_abort
|
||||
;;
|
||||
stgit-series)
|
||||
|
15
strbuf.c
15
strbuf.c
@ -322,7 +322,7 @@ int strbuf_readlink(struct strbuf *sb, const char *path, size_t hint)
|
||||
return -1;
|
||||
}
|
||||
|
||||
int strbuf_getline(struct strbuf *sb, FILE *fp, int term)
|
||||
int strbuf_getwholeline(struct strbuf *sb, FILE *fp, int term)
|
||||
{
|
||||
int ch;
|
||||
|
||||
@ -332,10 +332,10 @@ int strbuf_getline(struct strbuf *sb, FILE *fp, int term)
|
||||
|
||||
strbuf_reset(sb);
|
||||
while ((ch = fgetc(fp)) != EOF) {
|
||||
if (ch == term)
|
||||
break;
|
||||
strbuf_grow(sb, 1);
|
||||
sb->buf[sb->len++] = ch;
|
||||
if (ch == term)
|
||||
break;
|
||||
}
|
||||
if (ch == EOF && sb->len == 0)
|
||||
return EOF;
|
||||
@ -344,6 +344,15 @@ int strbuf_getline(struct strbuf *sb, FILE *fp, int term)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int strbuf_getline(struct strbuf *sb, FILE *fp, int term)
|
||||
{
|
||||
if (strbuf_getwholeline(sb, fp, term))
|
||||
return EOF;
|
||||
if (sb->buf[sb->len-1] == term)
|
||||
strbuf_setlen(sb, sb->len-1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int strbuf_read_file(struct strbuf *sb, const char *path, size_t hint)
|
||||
{
|
||||
int fd, len;
|
||||
|
1
strbuf.h
1
strbuf.h
@ -126,6 +126,7 @@ extern ssize_t strbuf_read(struct strbuf *, int fd, size_t hint);
|
||||
extern int strbuf_read_file(struct strbuf *sb, const char *path, size_t hint);
|
||||
extern int strbuf_readlink(struct strbuf *sb, const char *path, size_t hint);
|
||||
|
||||
extern int strbuf_getwholeline(struct strbuf *, FILE *, int);
|
||||
extern int strbuf_getline(struct strbuf *, FILE *, int);
|
||||
|
||||
extern void stripspace(struct strbuf *buf, int skip_comments);
|
||||
|
@ -3,9 +3,10 @@
|
||||
# Copyright (c) 2005 Amos Waterland
|
||||
#
|
||||
|
||||
test_description='git rebase should not destroy author information
|
||||
test_description='git rebase assorted tests
|
||||
|
||||
This test runs git rebase and checks that the author information is not lost.
|
||||
This test runs git rebase and checks that the author information is not lost
|
||||
among other things.
|
||||
'
|
||||
. ./test-lib.sh
|
||||
|
||||
@ -133,4 +134,25 @@ test_expect_success 'rebase -q is quiet' '
|
||||
test ! -s output.out
|
||||
'
|
||||
|
||||
q_to_cr () {
|
||||
tr Q '\015'
|
||||
}
|
||||
|
||||
test_expect_success 'Rebase a commit that sprinkles CRs in' '
|
||||
(
|
||||
echo "One"
|
||||
echo "TwoQ"
|
||||
echo "Three"
|
||||
echo "FQur"
|
||||
echo "Five"
|
||||
) | q_to_cr >CR &&
|
||||
git add CR &&
|
||||
test_tick &&
|
||||
git commit -a -m "A file with a line with CR" &&
|
||||
git tag file-with-cr &&
|
||||
git checkout HEAD^0 &&
|
||||
git rebase --onto HEAD^^ HEAD^ &&
|
||||
git diff --exit-code file-with-cr:CR HEAD:CR
|
||||
'
|
||||
|
||||
test_done
|
||||
|
Loading…
Reference in New Issue
Block a user