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:
Junio C Hamano 2009-08-21 18:47:44 -07:00
commit bcd45e27d8
7 changed files with 61 additions and 43 deletions

View File

@ -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);

View File

@ -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] ) {

View File

@ -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,

View File

@ -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)

View File

@ -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;

View File

@ -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);

View File

@ -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